Skip to content

Conversation

@ricardogarim
Copy link
Contributor

@ricardogarim ricardogarim commented Nov 17, 2025

Task: FB-44
Related PR: RocketChat/homeserver#300


Installing local homeserver version in Rocket.Chat

Run homeserver build and bundle:

bun run bundle:sdk

To test this locally, from the Rocket.Chat project root run:

yarn link ../homeserver/federation-bundle

Make sure the homeserver repository is cloned at the same directory level as the Rocket.Chat repository.

How to test without the UI

Run this in the browser console while your local Rocket.Chat instance is running.

async function getAuth() {
    return {
      'X-Auth-Token': localStorage.getItem('Meteor.loginToken'),
      'X-User-Id': localStorage.getItem('Meteor.userId'),
      'Content-Type': 'application/json'
    };
  }

  async function getInvites() {
    const res = await fetch('/api/v1/subscriptions.get', { headers: await getAuth() });
    const data = await res.json();
    return data.update.filter(s => s.status === 'INVITED');
  }

  async function getLatestInvite() {
    const invites = await getInvites();
    if (invites.length === 0) {
      console.log('no pending invites');
      return null;
    }
    invites.sort((a, b) => new Date(b._updatedAt) - new Date(a._updatedAt));
    return invites[0];
  }

  async function respondInvite(roomId, action) {
    const res = await fetch('/api/v1/rooms.invite', {
      method: 'POST',
      headers: await getAuth(),
      body: JSON.stringify({ roomId, action })
    });
    return res.json();
  }

  async function acceptLatest() {
    const invite = await getLatestInvite();
    if (!invite) return;
    const res = await respondInvite(invite.rid, 'accept');
    console.log('accept result:', res);
    return res;
  }

  async function rejectLatest() {
    const invite = await getLatestInvite();
    if (!invite) return;
    const res = await respondInvite(invite.rid, 'reject');
    console.log('reject result:', res);
    return res;
  }

  async function acceptInvite(roomId) {
    const res = await respondInvite(roomId, 'accept');
    console.log('accept result:', res);
    return res;
  }

  async function rejectInvite(roomId) {
    const res = await respondInvite(roomId, 'reject');
    console.log('reject result:', res);
    return res;
  }

  async function listInvites() {
    const invites = await getInvites();
    console.log(invites);
    return invites;
  }

  async function checkSubscriptionById(id) {
    const res = await fetch('/api/v1/subscriptions.get', { headers: await getAuth() });
    const data = await res.json();
    const sub = data.update.find(s => s._id === id);
    console.log(sub || 'not found');
    return sub;
  }

  async function checkSubscription(name) {
    const res = await fetch('/api/v1/subscriptions.get', { headers: await getAuth() });
    const data = await res.json();
    const sub = data.update.find(s => s.name === name || s.fname === name);
    console.log(sub || 'not found');
    return sub;
  }

Test cases

direction type scenario expected behavior
remote > RC channel (new) receive new channel invite create subscription with INVITED status
remote > RC channel (existing) receive invite to existing channel create subscription with INVITED; send system message that rcUser2 was invited
remote > RC dm (new) receive dm invite create subscription with INVITED
RC > RC channel (non-federated) local invites local do not use invites; add user directly without INVITED status
RC > RC channel (federated) local invites local create subscription with INVITED
RC > remote channel (federated) invite remote into RC federated channel create remote subscription with INVITED; RC sends system message “remote user invited”
RC > remote dm invite remote into RC DM create remote subscription with INVITED; RC sends system message “remote user invited”
remote > RC channel (federated) remote accepts remove INVITED; send system message “user joined”
remote > RC dm remote accepts remove INVITED; send system message “user joined”
remote > RC channel (federated) remote rejects remove subscription; send system message “user rejected invite”
remote > RC dm remote rejects remove subscription; send system message “user rejected invite”
RC > remote channel (federated) RC user accepts remote invite remove INVITED; send system message “user joined”
RC > remote dm RC user accepts remote invite remove INVITED; send system message “user joined”
RC > RC channel (federated) RC user accepts local invite remove INVITED; send system message “user joined”
RC > remote channel (federated) RC user rejects remote invite remove subscription; send system message “user rejected invite”
RC > remote dm RC user rejects remote invite remove subscription; send system message “user rejected invite”
RC > RC channel (federated) RC user rejects local invite remove subscription; send system message “local user rejected invite”
server A > server B > RC channel or dm third-server cases RC creates subscription with INVITED; sends system messages when invited / accepted / rejected

*while a subscription is in INVITED status, the RC user cannot perform any room actions except accept or reject the invite.
*to all RC started invites, we should test in three different scenarios: using new channel creation modal, room members add user sidepanel and slash command.

Summary by CodeRabbit

  • New Features

    • Added rooms.invite REST endpoint to accept or reject room invitations.
    • INVITED subscription status and inviter metadata to represent invitations.
    • Two new system message types for invite/reject with English translations.
    • New helpers and service methods to create, accept, and reject invited subscriptions.
  • Improvements

    • Explicit invite → accept/reject lifecycle with federation-aware flows.
    • Expanded end-to-end tests covering invite acceptance, rejection, and permissions.

✏️ Tip: You can customize this high-level summary in your review settings.

@dionisio-bot
Copy link
Contributor

dionisio-bot bot commented Nov 17, 2025

Looks like this PR is ready to merge! 🎉
If you have any trouble, please check the PR guidelines

@changeset-bot
Copy link

changeset-bot bot commented Nov 17, 2025

⚠️ No Changeset found

Latest commit: ff339d3

Merging this PR will not cause a version bump for any packages. If these changes should not result in a new version, you're good to go. If these changes should result in a version bump, you need to add a changeset.

This PR includes no changesets

When changesets are added to this PR, you'll see the packages that this PR includes changesets for and the associated semver types

Click here to learn what changesets are, and how to add one.

Click here if you're a maintainer who wants to add a changeset to this PR

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Nov 17, 2025

Walkthrough

Adds federated invitation handling: new POST /v1/rooms.invite endpoint invoking FederationMatrix.handleInvite, INVITED subscription status with inviter metadata, accept/reject flows and helpers, RoomService subscription helpers, message types/locales for invites, Matrix leave/send_leave routes, model/typing updates, and updated tests/helpers.

Changes

Cohort / File(s) Summary
REST API & public typings
apps/meteor/app/api/server/v1/rooms.ts, packages/rest-typings/src/v1/rooms.ts
Adds POST /v1/rooms.invite with AJV validation (isRoomsInviteProps) and handler calling FederationMatrix.handleInvite; updates REST typings and members return shape to include subscription snippet.
Federation core & matrix routes
ee/packages/federation-matrix/src/FederationMatrix.ts, ee/packages/federation-matrix/src/events/member.ts, ee/packages/federation-matrix/src/api/_matrix/invite.ts, ee/packages/federation-matrix/src/api/_matrix/make-leave.ts, ee/packages/federation-matrix/src/api/_matrix/send-leave.ts, ee/packages/federation-matrix/src/api/routes.ts
Introduces handleInvite, refactors invite/join/leave handlers, changes method signatures (e.g., createOrUpdateFederatedUser, createRoom), simplifies Matrix invite processing, and registers leave/send_leave routes.
Subscription types, models & DB methods
packages/core-typings/src/ISubscription.ts, packages/models/src/models/Subscriptions.ts, packages/model-typings/src/models/ISubscriptionsModel.ts
Adds SubscriptionStatus = 'INVITED'; extends ISubscription with status? and inviter?; adds findInvitedSubscription and acceptInvitationById; updates count query to ignore invitations.
Room models & model typings
packages/models/src/models/Rooms.ts, packages/model-typings/src/models/IRoomsModel.ts
Adds findOneFederatedByMrid(mrid, ...) to locate federated rooms by MRID.
Services & RoomService API
packages/core-services/src/types/IFederationMatrixService.ts, packages/core-services/src/types/IRoomService.ts, apps/meteor/server/services/room/service.ts
Adds handleInvite to federation service typings; makes IRoomService generic and adds createUserSubscription, performAcceptRoomInvite, performUserRemoval; RoomService exposes wrappers and implements createUserSubscription.
Accept/reject flows & helpers
apps/meteor/app/lib/server/functions/acceptRoomInvite.ts, apps/meteor/app/lib/server/functions/removeUserFromRoom.ts, apps/meteor/app/lib/server/functions/addUserToRoom.ts, apps/meteor/server/services/room/service.ts
Adds performAcceptRoomInvite; splits removal into performUserRemoval + wrapper; updates add-user flows to use Room.createUserSubscription and support INVITED status and inviter metadata.
Room creation & DMs
apps/meteor/app/lib/server/functions/createRoom.ts, apps/meteor/app/lib/server/functions/createDirectRoom.ts, apps/meteor/server/methods/createDirectMessage.ts
Reorders federation callbacks, uses extraData for federated DMs, removes federatedRoomId option, and marks federated member subscriptions as INVITED when applicable.
Publish fields, watchers & exports
apps/meteor/lib/publishFields.ts, apps/meteor/server/modules/watchers/watchers.module.ts, apps/meteor/server/lib/findUsersOfRoomOrderedByRole.ts, apps/meteor/server/lib/dataExport/exportRoomMessagesToFile.ts
Adds status and inviter to published subscription fields and watcher projections; findUsersOfRoomOrderedByRole now returns subscription snippet; export handles ui/uir message rendering.
Message types, registrations & i18n
apps/meteor/app/lib/lib/MessageTypes.ts, packages/apps-engine/src/definition/messages/MessageType.ts, packages/core-typings/src/IMessage/IMessage.ts, packages/message-types/src/registrations/common.ts, packages/i18n/src/locales/en.i18n.json
Adds message types ui and uir, registers system messages for invites/rejections, and adds i18n keys/translations.
Models typings & room service types
packages/core-services/src/types/IFederationMatrixService.ts, packages/core-services/src/types/IRoomService.ts, packages/model-typings/src/models/IRoomsModel.ts, packages/model-typings/src/models/ISubscriptionsModel.ts
Updates service/type signatures to reflect new methods and type changes (see cohorts above).
Tests & test helpers
apps/meteor/tests/data/rooms.helper.ts, ee/packages/federation-matrix/tests/end-to-end/room.spec.ts
Adds acceptRoomInvite and rejectRoomInvite test helpers; updates e2e tests to assert invite-centric events and permission checks.
Callbacks & federation hooks
apps/meteor/lib/callbacks.ts, apps/meteor/ee/server/hooks/federation/index.ts, apps/meteor/lib/callbacks/beforeCreateRoomCallback.ts
Adds extraData param to beforeCreateDirectMessage callback; adjusts federation hooks and prepareCreateRoomCallback extraData shape.
Package bumps
apps/meteor/package.json, ee/packages/federation-matrix/package.json, packages/core-services/package.json
Bumps @rocket.chat/federation-sdk from 0.3.2 to 0.3.3.

Sequence Diagram(s)

sequenceDiagram
    participant Client
    participant API as REST API (/v1/rooms.invite)
    participant FedMatrix as FederationMatrix
    participant Subs as Subscriptions Model
    participant RoomSvc as RoomService
    participant FedSDK as Federation SDK

    Client->>API: POST /v1/rooms.invite { roomId, action }
    API->>FedMatrix: handleInvite(roomId, currentUserId, action)
    FedMatrix->>Subs: findInvitedSubscription(roomId, userId)
    Subs-->>FedMatrix: subscription (status: INVITED) / null
    alt subscription exists and action == "accept"
        FedMatrix->>FedSDK: process/accept invite
        FedSDK-->>FedMatrix: result
        FedMatrix->>RoomSvc: performAcceptRoomInvite(room, subscription, user)
        RoomSvc->>Subs: acceptInvitationById(subscriptionId)
        RoomSvc->>RoomSvc: run hooks, save system message, post-join callbacks
    else subscription exists and action == "reject"
        FedMatrix->>FedSDK: reject invite
        FedSDK-->>FedMatrix: result
        FedMatrix->>Subs: optional cleanup/notify
    else no invited subscription
        FedMatrix-->>API: failure (400/403)
    end
    FedMatrix-->>API: success/failure
    API-->>Client: 200 / error
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

  • Areas needing careful review:
    • ee/packages/federation-matrix: new handleInvite, altered createOrUpdateFederatedUser/createRoom and invite flows, and Matrix invite route changes.
    • apps/meteor server functions: performAcceptRoomInvite, performUserRemoval, createUserSubscription, and Apps Engine callback integration.
    • Models/aggregations and published fields: subscription status/inviter projection changes and count query behavior.

Possibly related PRs

Suggested reviewers

  • ggazzo
  • rodrigok

Poem

🐇 I hopped through invites with a twitch of my nose,
INVITED carrots trail where federation goes.
Accept or reject — a polite little hop,
Callbacks and messages — the rabbit won't stop.
🥕 Hooray for invites, now sent from the burrow!

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 15.38% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'feat(federation): add room invites support' clearly and concisely describes the main change, focusing on federation room invites functionality.
Linked Issues check ✅ Passed The PR implements federation room invites support with system message handling, subscription status tracking, and acceptance/rejection flows as required by FB-44.
Out of Scope Changes check ✅ Passed All changes are directly related to federation room invites: new REST endpoint, message types, subscription fields, federation logic, and supporting infrastructure for invite lifecycle.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch feat/invites

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@ricardogarim ricardogarim marked this pull request as ready for review November 17, 2025 10:56
@ricardogarim ricardogarim requested review from a team as code owners November 17, 2025 10:56
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
ee/packages/federation-matrix/src/api/_matrix/profiles.ts (1)

368-386: Inconsistent null handling between the two response paths needs fixing.

The optional chaining added on line 376 (response?.[field]) indicates response may be undefined. However, line 383 returns response directly without the same safety check, creating an inconsistency.

Evidence from the codebase shows similar SDK methods can return null/undefined:

  • downloadFromRemoteServer explicitly checks for null (MatrixMediaService.ts:107)
  • getEventById checks if undefined before returning (transactions.ts:443)

If queryProfile can return undefined:

  • Both code paths (line 376 and 383) need consistent null handling
  • Returning HTTP 200 with undefined body may violate the schema contract

Recommendation: Add explicit error handling if response is null/undefined, or document that queryProfile guarantees a valid object to justify removing the optional chaining.

🧹 Nitpick comments (8)
packages/i18n/src/locales/en.i18n.json (1)

5565-5566: Copy tweak for article consistency.

Use “the” as in the previous line (“to the room”).

-  "User_rejected_invitation_to_room": "rejected invitation to room",
+  "User_rejected_invitation_to_room": "rejected the invitation to the room",
apps/meteor/app/api/server/v1/rooms.ts (1)

1-1: rooms.invite route wiring looks good; minor nits on validation/error handling

The new rooms.invite route correctly restricts actions to the authenticated user (via this.userId in FederationMatrix.handleInvite) and validates the payload via isRoomsInviteProps, which is great for safety.

Two small suggestions:

  • Since isRoomsInviteProps already constrains subscriptionId and action, the explicit !subscriptionId and action !== 'accept' && action !== 'reject' checks are redundant; you can rely purely on ajv to avoid duplicate validation logic.
  • In the catch block, you currently only surface the error message to the client; consider also logging the raw error server‑side (if not already logged in handleInvite) to aid debugging of Matrix/federation issues.

Also applies to: 18-19, 1079-1104

packages/core-services/src/types/IRoomService.ts (1)

34-48: addUserToRoom options extension matches subscription invite metadata

Adding invited?: boolean and federation?: { inviteEventId?: string; inviterUsername?: string } to the addUserToRoom options cleanly exposes the invite metadata used by the new Matrix flows and matches the ISubscription shape.

If you expect this metadata to evolve, you might consider typing federation as a Pick<ISubscription, 'federation'>['federation'] to avoid duplicating the structure, but the current explicit interface is also fine.

ee/packages/federation-matrix/src/FederationMatrix.ts (1)

1-1: handleInvite implementation is consistent; consider centralizing Matrix user ID derivation

The new handleInvite method correctly:

  • Ensures the subscription belongs to the current user and is flagged invited: true.
  • Requires federation.inviteEventId to be present.
  • Looks up the user and emits appropriate system messages for accept (uj) and reject (uir).

A couple of small improvements:

  • You compute matrixUserId before checking user.username; for readability, consider moving the !user.username guard before constructing the local MXID branch.
  • The logic that turns a IUser into a Matrix user ID now exists in several places (here and in helpers). Extracting a shared helper for "user → Matrix ID" would reduce drift if the federation rules change.

Also applies to: 10-10, 902-937

ee/packages/federation-matrix/src/events/helpers.ts (1)

12-84: Federated user/room helpers look correct; minor cleanups possible

The helpers nicely encapsulate the recurring patterns:

  • getOrCreateFederatedUser correctly distinguishes local vs remote Matrix IDs via getUsernameServername, avoids auto‑creating local users, and delegates remote creation to createOrUpdateFederatedUser.
  • getOrCreateFederatedRoom uses the Matrix room ID as the lookup key (federation.mrid) and passes federatedRoomId/fname into Room.create, which is consistent with the new ICreateRoomOptions fields.

Small nits:

  • The _inviterMatrixId parameter is currently unused; if there’s no near‑term use planned, you can drop it to keep the signature minimal.
  • For clarity, it might be worth renaming the first parameter of getOrCreateFederatedRoom to something like matrixRoomId to distinguish it from the human display name.
apps/meteor/app/lib/server/functions/addUserToRoom.ts (1)

22-41: Invite/federation plumbing in addUserToRoom is coherent; tiny message nit

The changes here line up well with the new invite flow:

  • invited and federation options are threaded through and conditionally added to the subscription document, matching the new ISubscription fields.
  • The system-message logic now:
    • Requires inviter.username before using inviter‑specific branches.
    • Emits ui when invited is true, carrying the inviter as u in the payload, which matches the new invite message type.

Minor nit: the ui branch doesn’t reuse the extraData object or set an explicit ts like the au/team messages. If you want identical timestamp semantics, you could pass { ts: now, u: { ... } } instead of constructing a separate object.

Also applies to: 102-113, 123-147

ee/packages/federation-matrix/src/events/member.ts (2)

55-111: handleInvite flow is solid; tighten room name fallback and type usage

The invite handler correctly:

  • Resolves/creates inviter and invitee via getOrCreateFederatedUser.
  • Derives room type ('d' for direct, 'c' otherwise) and a human‑readable roomFName.
  • Ensures a federated room exists via getOrCreateFederatedRoom, then calls Room.addUserToRoom with invited and federation metadata so downstream logic can treat it as a pending invite.

Two small points to consider:

  • The fallback roomName = \${room_id}:${roomOriginDomain}`will produce strings like!abc:server:undefinedwhenroomOriginDomainis missing; you might want to default to justroom_idin that case to avoid oddfname` values.
  • _inviterMatrixId passed into getOrCreateFederatedRoom is unused; either remove the parameter or start using it (e.g., if you later need the Matrix ID inside room creation).

113-158: Join handler correctly distinguishes direct joins vs invite acceptance

The join handler behavior looks good:

  • If no local room exists yet, it falls back to membershipJoinAction, preserving the legacy behavior.
  • If there’s no subscription for the joining user, it also delegates to membershipJoinAction, treating it as a regular join.
  • When a subscription exists, it interprets the event as “accepting an invite” and unsets invited and the invite metadata while reopening the subscription.

One minor improvement: you might want to guard the “accept invite” path with if (subscription.invited) and simply return when invited is falsy, to avoid unnecessary $unset/$set updates on repeated join events for already‑joined users.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

Disabled knowledge base sources:

  • Jira integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between e1682d2 and 279d97b.

📒 Files selected for processing (20)
  • apps/meteor/app/api/server/v1/rooms.ts (3 hunks)
  • apps/meteor/app/lib/lib/MessageTypes.ts (1 hunks)
  • apps/meteor/app/lib/server/functions/addUserToRoom.ts (4 hunks)
  • apps/meteor/lib/publishFields.ts (1 hunks)
  • apps/meteor/server/lib/dataExport/exportRoomMessagesToFile.ts (1 hunks)
  • apps/meteor/server/modules/watchers/watchers.module.ts (1 hunks)
  • ee/packages/federation-matrix/src/FederationMatrix.ts (3 hunks)
  • ee/packages/federation-matrix/src/api/_matrix/invite.ts (1 hunks)
  • ee/packages/federation-matrix/src/api/_matrix/profiles.ts (1 hunks)
  • ee/packages/federation-matrix/src/api/_matrix/rooms.ts (1 hunks)
  • ee/packages/federation-matrix/src/events/helpers.ts (1 hunks)
  • ee/packages/federation-matrix/src/events/member.ts (2 hunks)
  • packages/apps-engine/src/definition/messages/MessageType.ts (1 hunks)
  • packages/core-services/src/types/IFederationMatrixService.ts (2 hunks)
  • packages/core-services/src/types/IRoomService.ts (1 hunks)
  • packages/core-typings/src/IMessage/IMessage.ts (1 hunks)
  • packages/core-typings/src/ISubscription.ts (2 hunks)
  • packages/i18n/src/locales/en.i18n.json (2 hunks)
  • packages/message-types/src/registrations/common.ts (1 hunks)
  • packages/rest-typings/src/v1/rooms.ts (2 hunks)
🧰 Additional context used
🧠 Learnings (9)
📓 Common learnings
Learnt from: ricardogarim
Repo: RocketChat/Rocket.Chat PR: 37205
File: ee/packages/federation-matrix/src/FederationMatrix.ts:296-301
Timestamp: 2025-10-28T16:53:42.761Z
Learning: In the Rocket.Chat federation-matrix integration (ee/packages/federation-matrix/), the createRoom method from rocket.chat/federation-sdk will support a 4-argument signature (userId, roomName, visibility, displayName) in newer versions. Code using this 4-argument call is forward-compatible with planned library updates and should not be flagged as an error.
Learnt from: ricardogarim
Repo: RocketChat/Rocket.Chat PR: 37205
File: ee/packages/federation-matrix/src/FederationMatrix.ts:296-301
Timestamp: 2025-10-28T16:53:42.761Z
Learning: In the Rocket.Chat federation-matrix integration (ee/packages/federation-matrix/), the createRoom method from rocket.chat/federation-sdk will support a 4-argument signature (userId, roomName, visibility, displayName) in newer versions. Code using this 4-argument call is forward-compatible with planned library updates and should not be flagged as an error.
Learnt from: ricardogarim
Repo: RocketChat/Rocket.Chat PR: 37377
File: apps/meteor/ee/server/hooks/federation/index.ts:86-88
Timestamp: 2025-11-04T16:49:19.107Z
Learning: In Rocket.Chat's federation system (apps/meteor/ee/server/hooks/federation/), permission checks follow two distinct patterns: (1) User-initiated federation actions (creating rooms, adding users to federated rooms, joining from invites) should throw MeteorError to inform users they lack 'access-federation' permission. (2) Remote server-initiated federation events should silently skip/ignore when users lack permission. The beforeAddUserToRoom hook only executes for local user-initiated actions, so throwing an error there is correct. Remote federation events are handled separately by the federation Matrix package with silent skipping logic.
📚 Learning: 2025-10-28T16:53:42.761Z
Learnt from: ricardogarim
Repo: RocketChat/Rocket.Chat PR: 37205
File: ee/packages/federation-matrix/src/FederationMatrix.ts:296-301
Timestamp: 2025-10-28T16:53:42.761Z
Learning: In the Rocket.Chat federation-matrix integration (ee/packages/federation-matrix/), the createRoom method from rocket.chat/federation-sdk will support a 4-argument signature (userId, roomName, visibility, displayName) in newer versions. Code using this 4-argument call is forward-compatible with planned library updates and should not be flagged as an error.

Applied to files:

  • ee/packages/federation-matrix/src/FederationMatrix.ts
  • ee/packages/federation-matrix/src/events/member.ts
  • ee/packages/federation-matrix/src/events/helpers.ts
  • apps/meteor/app/lib/server/functions/addUserToRoom.ts
  • ee/packages/federation-matrix/src/api/_matrix/invite.ts
  • packages/core-services/src/types/IFederationMatrixService.ts
  • apps/meteor/app/api/server/v1/rooms.ts
  • apps/meteor/server/lib/dataExport/exportRoomMessagesToFile.ts
  • packages/core-services/src/types/IRoomService.ts
  • ee/packages/federation-matrix/src/api/_matrix/rooms.ts
📚 Learning: 2025-11-05T21:04:35.787Z
Learnt from: sampaiodiego
Repo: RocketChat/Rocket.Chat PR: 37357
File: ee/packages/federation-matrix/src/setup.ts:103-120
Timestamp: 2025-11-05T21:04:35.787Z
Learning: In Rocket.Chat's federation-matrix setup (ee/packages/federation-matrix/src/setup.ts and apps/meteor/ee/server/startup/federation.ts), configureFederationMatrixSettings does not need to be called before setupFederationMatrix. The SDK's init() establishes infrastructure (database, event handlers, APIs) first, and the configuration can be applied later via settings watchers before actual federation events are processed. The config only matters when events actually occur, at which point all infrastructure is already configured.

Applied to files:

  • ee/packages/federation-matrix/src/FederationMatrix.ts
  • ee/packages/federation-matrix/src/events/member.ts
  • ee/packages/federation-matrix/src/events/helpers.ts
  • ee/packages/federation-matrix/src/api/_matrix/invite.ts
  • packages/core-services/src/types/IFederationMatrixService.ts
  • apps/meteor/app/api/server/v1/rooms.ts
📚 Learning: 2025-11-04T16:49:19.107Z
Learnt from: ricardogarim
Repo: RocketChat/Rocket.Chat PR: 37377
File: apps/meteor/ee/server/hooks/federation/index.ts:86-88
Timestamp: 2025-11-04T16:49:19.107Z
Learning: In Rocket.Chat's federation system (apps/meteor/ee/server/hooks/federation/), permission checks follow two distinct patterns: (1) User-initiated federation actions (creating rooms, adding users to federated rooms, joining from invites) should throw MeteorError to inform users they lack 'access-federation' permission. (2) Remote server-initiated federation events should silently skip/ignore when users lack permission. The beforeAddUserToRoom hook only executes for local user-initiated actions, so throwing an error there is correct. Remote federation events are handled separately by the federation Matrix package with silent skipping logic.

Applied to files:

  • ee/packages/federation-matrix/src/FederationMatrix.ts
  • ee/packages/federation-matrix/src/events/member.ts
  • ee/packages/federation-matrix/src/events/helpers.ts
  • apps/meteor/app/lib/server/functions/addUserToRoom.ts
  • ee/packages/federation-matrix/src/api/_matrix/invite.ts
  • packages/core-services/src/types/IFederationMatrixService.ts
  • apps/meteor/app/api/server/v1/rooms.ts
📚 Learning: 2025-09-19T15:15:04.642Z
Learnt from: rodrigok
Repo: RocketChat/Rocket.Chat PR: 36991
File: apps/meteor/server/services/federation/infrastructure/rocket-chat/adapters/Settings.ts:219-221
Timestamp: 2025-09-19T15:15:04.642Z
Learning: The Federation_Matrix_homeserver_domain setting in apps/meteor/server/services/federation/infrastructure/rocket-chat/adapters/Settings.ts is part of the old federation system and is being deprecated/removed, so configuration issues with this setting should not be flagged for improvement.

Applied to files:

  • ee/packages/federation-matrix/src/FederationMatrix.ts
  • apps/meteor/lib/publishFields.ts
  • ee/packages/federation-matrix/src/events/member.ts
  • ee/packages/federation-matrix/src/events/helpers.ts
  • apps/meteor/app/lib/server/functions/addUserToRoom.ts
  • ee/packages/federation-matrix/src/api/_matrix/invite.ts
  • packages/core-services/src/types/IFederationMatrixService.ts
  • apps/meteor/app/api/server/v1/rooms.ts
  • ee/packages/federation-matrix/src/api/_matrix/rooms.ts
📚 Learning: 2025-09-25T09:59:26.461Z
Learnt from: Dnouv
Repo: RocketChat/Rocket.Chat PR: 37057
File: packages/apps-engine/src/definition/accessors/IUserRead.ts:23-27
Timestamp: 2025-09-25T09:59:26.461Z
Learning: AppUserBridge.getUserRoomIds in apps/meteor/app/apps/server/bridges/users.ts always returns an array of strings by mapping subscription documents to room IDs, never undefined, even when user has no room subscriptions.

Applied to files:

  • ee/packages/federation-matrix/src/FederationMatrix.ts
  • ee/packages/federation-matrix/src/events/member.ts
  • ee/packages/federation-matrix/src/events/helpers.ts
  • apps/meteor/app/lib/server/functions/addUserToRoom.ts
  • packages/core-services/src/types/IFederationMatrixService.ts
  • apps/meteor/app/api/server/v1/rooms.ts
  • packages/core-services/src/types/IRoomService.ts
📚 Learning: 2025-09-25T09:59:26.461Z
Learnt from: Dnouv
Repo: RocketChat/Rocket.Chat PR: 37057
File: packages/apps-engine/src/definition/accessors/IUserRead.ts:23-27
Timestamp: 2025-09-25T09:59:26.461Z
Learning: AppUserBridge.getUserRoomIds in apps/meteor/app/apps/server/bridges/users.ts always returns an array of strings (mapping subscription documents to room IDs), never undefined, even when user has no room subscriptions.

Applied to files:

  • ee/packages/federation-matrix/src/FederationMatrix.ts
  • ee/packages/federation-matrix/src/events/member.ts
  • ee/packages/federation-matrix/src/events/helpers.ts
  • apps/meteor/app/lib/server/functions/addUserToRoom.ts
  • packages/core-services/src/types/IFederationMatrixService.ts
  • apps/meteor/app/api/server/v1/rooms.ts
  • packages/core-services/src/types/IRoomService.ts
📚 Learning: 2025-10-06T20:32:23.658Z
Learnt from: d-gubert
Repo: RocketChat/Rocket.Chat PR: 37152
File: packages/apps-engine/tests/test-data/utilities.ts:557-573
Timestamp: 2025-10-06T20:32:23.658Z
Learning: In packages/apps-engine/tests/test-data/utilities.ts, the field name `isSubscripbedViaBundle` in the `IMarketplaceSubscriptionInfo` type should not be flagged as a typo, as it may match the upstream API's field name.

Applied to files:

  • apps/meteor/lib/publishFields.ts
  • packages/core-typings/src/ISubscription.ts
  • apps/meteor/server/modules/watchers/watchers.module.ts
📚 Learning: 2025-09-25T09:59:26.461Z
Learnt from: Dnouv
Repo: RocketChat/Rocket.Chat PR: 37057
File: packages/apps-engine/src/definition/accessors/IUserRead.ts:23-27
Timestamp: 2025-09-25T09:59:26.461Z
Learning: UserBridge.doGetUserRoomIds in packages/apps-engine/src/server/bridges/UserBridge.ts has a bug where it implicitly returns undefined when the app lacks read permission (missing return statement in the else case of the permission check).

Applied to files:

  • apps/meteor/app/lib/server/functions/addUserToRoom.ts
🧬 Code graph analysis (6)
ee/packages/federation-matrix/src/FederationMatrix.ts (2)
packages/core-typings/src/ISubscription.ts (1)
  • ISubscription (10-81)
packages/core-typings/src/IUser.ts (2)
  • IUser (186-255)
  • isUserNativeFederated (276-277)
ee/packages/federation-matrix/src/events/member.ts (3)
ee/packages/federation-matrix/src/FederationMatrix.ts (1)
  • handleInvite (902-937)
ee/packages/federation-matrix/src/events/helpers.ts (2)
  • getOrCreateFederatedUser (12-48)
  • getOrCreateFederatedRoom (50-84)
packages/core-typings/src/IRoom.ts (1)
  • RoomID (12-12)
ee/packages/federation-matrix/src/events/helpers.ts (4)
packages/core-typings/src/IUser.ts (1)
  • IUser (186-255)
ee/packages/federation-matrix/src/FederationMatrix.ts (3)
  • getUsernameServername (73-85)
  • createOrUpdateFederatedUser (92-133)
  • extractDomainFromMatrixUserId (60-66)
packages/core-typings/src/IRoom.ts (2)
  • RoomID (12-12)
  • IRoom (21-95)
packages/core-services/src/index.ts (1)
  • Room (169-169)
apps/meteor/app/lib/server/functions/addUserToRoom.ts (1)
packages/core-services/src/index.ts (1)
  • Message (184-184)
packages/core-services/src/types/IFederationMatrixService.ts (2)
packages/core-typings/src/ISubscription.ts (1)
  • ISubscription (10-81)
packages/core-typings/src/IUser.ts (1)
  • IUser (186-255)
apps/meteor/app/api/server/v1/rooms.ts (2)
packages/rest-typings/src/v1/rooms.ts (1)
  • isRoomsInviteProps (712-712)
ee/packages/federation-matrix/src/FederationMatrix.ts (1)
  • FederationMatrix (137-938)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (3)
  • GitHub Check: 📦 Build Packages
  • GitHub Check: CodeQL-Build
  • GitHub Check: CodeQL-Build
🔇 Additional comments (17)
ee/packages/federation-matrix/src/api/_matrix/rooms.ts (1)

189-189: LGTM! Good defensive programming.

The optional chaining prevents potential runtime errors when room names are undefined during filtering.

apps/meteor/server/lib/dataExport/exportRoomMessagesToFile.ts (1)

82-89: LGTM! Consistent implementation.

The new message type handlers follow the established pattern and properly apply username obfuscation for the 'ui' case, consistent with similar user action types like 'au'.

apps/meteor/lib/publishFields.ts (1)

45-46: LGTM! Subscription field additions.

The new invited and federation fields extend subscription projections to support the federation invite workflow.

packages/core-services/src/types/IFederationMatrixService.ts (2)

1-1: LGTM! Required import for new method.

Adding ISubscription import supports the new handleInvite method signature.


31-31: LGTM! Well-typed method signature.

The handleInvite method signature is clear and properly typed with union type for the action parameter.

packages/core-typings/src/IMessage/IMessage.ts (1)

71-72: LGTM! Type definitions for new message types.

The new 'ui' and 'uir' message type literals are properly added to the MessageTypes array, enabling type-safe usage across the codebase.

packages/apps-engine/src/definition/messages/MessageType.ts (1)

78-81: LGTM! Clear type definitions with descriptive comments.

The new message types are well-documented and properly integrated into the MessageType union.

packages/message-types/src/registrations/common.ts (1)

28-38: LGTM! Consistent system message registrations.

The new 'ui' and 'uir' message type registrations follow established patterns and properly integrate with the i18n system.

ee/packages/federation-matrix/src/api/_matrix/invite.ts (3)

1-10: LGTM!

The import changes are clean and all imported symbols are properly utilized in the code.


174-271: LGTM!

The route handler correctly validates parameters, checks permissions, and returns appropriate HTTP status codes. The permission check at line 220 appropriately returns a 403 response to inform the remote federation server that the user cannot access federation, which is the correct behavior for an HTTP endpoint.


136-172: The acceptInvite function is actively used in the codebase and is not dead code.

Verification confirms that acceptInvite is imported and called in ee/packages/federation-matrix/src/FederationMatrix.ts at line 570 within an invite handling promise chain. The original review comment's concern was based on incomplete information.

Likely an incorrect or invalid review comment.

packages/rest-typings/src/v1/rooms.ts (2)

691-712: LGTM!

The type definition and schema are well-structured with proper validation. The schema correctly enforces required fields, constrains the action to valid values, and prevents additional properties.


895-897: LGTM!

The endpoint definition is consistent with the rest of the API and correctly references the new RoomsInviteProps type.

packages/core-typings/src/ISubscription.ts (1)

76-80: LGTM!

The new fields are well-structured to support federation invite tracking. The invited?: true pattern effectively creates a boolean flag that defaults to undefined, and the federation object provides appropriate metadata for federated invites.

packages/i18n/src/locales/en.i18n.json (1)

3366-3367: Message type labels properly wired; no action needed.

The new types ui and uir are correctly defined in MessageTypes.ts (lines 33–39) with matching i18n labels in the JSON file. The Hide_System_Messages setting uses MessageTypesValues dynamically, automatically including all registered message types. Verification confirms proper wiring across the system.

apps/meteor/server/modules/watchers/watchers.module.ts (1)

140-147: Including invited/federation in watched subscription fields is appropriate

Extending the Pick<ISubscription, ...> to include invited and federation keeps the watcher’s projection in sync with subscriptionFields and ensures invite state is broadcast to other instances/clients.

ee/packages/federation-matrix/src/events/helpers.ts (1)

86-103: extractDomainFromId / extractUsernameFromMatrixId are safe, defensive wrappers

Both extraction helpers handle malformed IDs by logging and returning a fallback, which is appropriate for event‑driven federation code where robustness beats hard failures.

No issues here; just ensure call sites are prepared for the empty‑string / original‑ID fallbacks when verification is important.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
apps/meteor/app/lib/server/functions/removeUserFromRoom.ts (1)

35-37: Critical: invited field missing from projection.

The subscription is fetched with only { _id: 1 } in the projection, but line 48 checks subscription.invited. Since invited is not included in the projection, it will always be undefined, causing the new conditional branch (lines 48-49) to never execute.

Apply this diff to include the invited field:

 const subscription = await Subscriptions.findOneByRoomIdAndUserId(rid, user._id, {
-	projection: { _id: 1 },
+	projection: { _id: 1, invited: 1 },
 });
🧹 Nitpick comments (1)
ee/packages/federation-matrix/src/events/member.ts (1)

71-71: Remove redundant membership check.

Line 71 checks content.membership === 'invite', but this function is only called when membership is already 'invite' (line 184 in the dispatcher). This condition is always true here.

Apply this diff:

-const roomType = content.membership === 'invite' && content?.is_direct ? 'd' : 'c';
+const roomType = content?.is_direct ? 'd' : 'c';
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

Disabled knowledge base sources:

  • Jira integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between 279d97b and e4bc153.

📒 Files selected for processing (5)
  • apps/meteor/app/lib/lib/MessageTypes.ts (1 hunks)
  • apps/meteor/app/lib/server/functions/removeUserFromRoom.ts (1 hunks)
  • ee/packages/federation-matrix/src/FederationMatrix.ts (2 hunks)
  • ee/packages/federation-matrix/src/events/member.ts (2 hunks)
  • packages/core-typings/src/ISubscription.ts (2 hunks)
🚧 Files skipped from review as they are similar to previous changes (2)
  • packages/core-typings/src/ISubscription.ts
  • apps/meteor/app/lib/lib/MessageTypes.ts
🧰 Additional context used
🧠 Learnings (9)
📓 Common learnings
Learnt from: ricardogarim
Repo: RocketChat/Rocket.Chat PR: 37377
File: apps/meteor/ee/server/hooks/federation/index.ts:86-88
Timestamp: 2025-11-04T16:49:19.107Z
Learning: In Rocket.Chat's federation system (apps/meteor/ee/server/hooks/federation/), permission checks follow two distinct patterns: (1) User-initiated federation actions (creating rooms, adding users to federated rooms, joining from invites) should throw MeteorError to inform users they lack 'access-federation' permission. (2) Remote server-initiated federation events should silently skip/ignore when users lack permission. The beforeAddUserToRoom hook only executes for local user-initiated actions, so throwing an error there is correct. Remote federation events are handled separately by the federation Matrix package with silent skipping logic.
Learnt from: ricardogarim
Repo: RocketChat/Rocket.Chat PR: 37205
File: ee/packages/federation-matrix/src/FederationMatrix.ts:296-301
Timestamp: 2025-10-28T16:53:42.761Z
Learning: In the Rocket.Chat federation-matrix integration (ee/packages/federation-matrix/), the createRoom method from rocket.chat/federation-sdk will support a 4-argument signature (userId, roomName, visibility, displayName) in newer versions. Code using this 4-argument call is forward-compatible with planned library updates and should not be flagged as an error.
Learnt from: ricardogarim
Repo: RocketChat/Rocket.Chat PR: 37205
File: ee/packages/federation-matrix/src/FederationMatrix.ts:296-301
Timestamp: 2025-10-28T16:53:42.761Z
Learning: In the Rocket.Chat federation-matrix integration (ee/packages/federation-matrix/), the createRoom method from rocket.chat/federation-sdk will support a 4-argument signature (userId, roomName, visibility, displayName) in newer versions. Code using this 4-argument call is forward-compatible with planned library updates and should not be flagged as an error.
📚 Learning: 2025-10-28T16:53:42.761Z
Learnt from: ricardogarim
Repo: RocketChat/Rocket.Chat PR: 37205
File: ee/packages/federation-matrix/src/FederationMatrix.ts:296-301
Timestamp: 2025-10-28T16:53:42.761Z
Learning: In the Rocket.Chat federation-matrix integration (ee/packages/federation-matrix/), the createRoom method from rocket.chat/federation-sdk will support a 4-argument signature (userId, roomName, visibility, displayName) in newer versions. Code using this 4-argument call is forward-compatible with planned library updates and should not be flagged as an error.

Applied to files:

  • ee/packages/federation-matrix/src/FederationMatrix.ts
  • apps/meteor/app/lib/server/functions/removeUserFromRoom.ts
  • ee/packages/federation-matrix/src/events/member.ts
📚 Learning: 2025-11-04T16:49:19.107Z
Learnt from: ricardogarim
Repo: RocketChat/Rocket.Chat PR: 37377
File: apps/meteor/ee/server/hooks/federation/index.ts:86-88
Timestamp: 2025-11-04T16:49:19.107Z
Learning: In Rocket.Chat's federation system (apps/meteor/ee/server/hooks/federation/), permission checks follow two distinct patterns: (1) User-initiated federation actions (creating rooms, adding users to federated rooms, joining from invites) should throw MeteorError to inform users they lack 'access-federation' permission. (2) Remote server-initiated federation events should silently skip/ignore when users lack permission. The beforeAddUserToRoom hook only executes for local user-initiated actions, so throwing an error there is correct. Remote federation events are handled separately by the federation Matrix package with silent skipping logic.

Applied to files:

  • ee/packages/federation-matrix/src/FederationMatrix.ts
  • apps/meteor/app/lib/server/functions/removeUserFromRoom.ts
  • ee/packages/federation-matrix/src/events/member.ts
📚 Learning: 2025-11-05T21:04:35.787Z
Learnt from: sampaiodiego
Repo: RocketChat/Rocket.Chat PR: 37357
File: ee/packages/federation-matrix/src/setup.ts:103-120
Timestamp: 2025-11-05T21:04:35.787Z
Learning: In Rocket.Chat's federation-matrix setup (ee/packages/federation-matrix/src/setup.ts and apps/meteor/ee/server/startup/federation.ts), configureFederationMatrixSettings does not need to be called before setupFederationMatrix. The SDK's init() establishes infrastructure (database, event handlers, APIs) first, and the configuration can be applied later via settings watchers before actual federation events are processed. The config only matters when events actually occur, at which point all infrastructure is already configured.

Applied to files:

  • ee/packages/federation-matrix/src/FederationMatrix.ts
  • ee/packages/federation-matrix/src/events/member.ts
📚 Learning: 2025-09-19T15:15:04.642Z
Learnt from: rodrigok
Repo: RocketChat/Rocket.Chat PR: 36991
File: apps/meteor/server/services/federation/infrastructure/rocket-chat/adapters/Settings.ts:219-221
Timestamp: 2025-09-19T15:15:04.642Z
Learning: The Federation_Matrix_homeserver_domain setting in apps/meteor/server/services/federation/infrastructure/rocket-chat/adapters/Settings.ts is part of the old federation system and is being deprecated/removed, so configuration issues with this setting should not be flagged for improvement.

Applied to files:

  • ee/packages/federation-matrix/src/FederationMatrix.ts
  • ee/packages/federation-matrix/src/events/member.ts
📚 Learning: 2025-09-25T09:59:26.461Z
Learnt from: Dnouv
Repo: RocketChat/Rocket.Chat PR: 37057
File: packages/apps-engine/src/definition/accessors/IUserRead.ts:23-27
Timestamp: 2025-09-25T09:59:26.461Z
Learning: AppUserBridge.getUserRoomIds in apps/meteor/app/apps/server/bridges/users.ts always returns an array of strings by mapping subscription documents to room IDs, never undefined, even when user has no room subscriptions.

Applied to files:

  • ee/packages/federation-matrix/src/FederationMatrix.ts
  • apps/meteor/app/lib/server/functions/removeUserFromRoom.ts
  • ee/packages/federation-matrix/src/events/member.ts
📚 Learning: 2025-09-25T09:59:26.461Z
Learnt from: Dnouv
Repo: RocketChat/Rocket.Chat PR: 37057
File: packages/apps-engine/src/definition/accessors/IUserRead.ts:23-27
Timestamp: 2025-09-25T09:59:26.461Z
Learning: AppUserBridge.getUserRoomIds in apps/meteor/app/apps/server/bridges/users.ts always returns an array of strings (mapping subscription documents to room IDs), never undefined, even when user has no room subscriptions.

Applied to files:

  • ee/packages/federation-matrix/src/FederationMatrix.ts
  • apps/meteor/app/lib/server/functions/removeUserFromRoom.ts
  • ee/packages/federation-matrix/src/events/member.ts
📚 Learning: 2025-09-25T09:59:26.461Z
Learnt from: Dnouv
Repo: RocketChat/Rocket.Chat PR: 37057
File: packages/apps-engine/src/definition/accessors/IUserRead.ts:23-27
Timestamp: 2025-09-25T09:59:26.461Z
Learning: UserBridge.doGetUserRoomIds in packages/apps-engine/src/server/bridges/UserBridge.ts has a bug where it implicitly returns undefined when the app lacks read permission (missing return statement in the else case of the permission check).

Applied to files:

  • apps/meteor/app/lib/server/functions/removeUserFromRoom.ts
📚 Learning: 2025-11-10T19:06:20.146Z
Learnt from: MartinSchoeler
Repo: RocketChat/Rocket.Chat PR: 37408
File: apps/meteor/client/views/admin/ABAC/useRoomAttributeOptions.tsx:53-69
Timestamp: 2025-11-10T19:06:20.146Z
Learning: In the Rocket.Chat repository, do not provide suggestions or recommendations about code sections marked with TODO comments. The maintainers have already identified these as future work and external reviewers lack the full context about implementation plans and timing.

Applied to files:

  • ee/packages/federation-matrix/src/events/member.ts
🧬 Code graph analysis (2)
ee/packages/federation-matrix/src/FederationMatrix.ts (2)
packages/core-typings/src/ISubscription.ts (1)
  • ISubscription (10-81)
packages/core-typings/src/IUser.ts (2)
  • IUser (186-255)
  • isUserNativeFederated (276-277)
ee/packages/federation-matrix/src/events/member.ts (2)
ee/packages/federation-matrix/src/FederationMatrix.ts (1)
  • handleInvite (902-935)
ee/packages/federation-matrix/src/events/helpers.ts (2)
  • getOrCreateFederatedUser (12-48)
  • getOrCreateFederatedRoom (50-84)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (3)
  • GitHub Check: 📦 Build Packages
  • GitHub Check: CodeQL-Build
  • GitHub Check: CodeQL-Build
🔇 Additional comments (5)
apps/meteor/app/lib/server/functions/removeUserFromRoom.ts (1)

48-49: Verify the semantic correctness of message type 'uir'—this is a confirmed issue.

The 'uir' message type is defined as "user rejected invitation to room" (per the comment in apps/meteor/app/lib/lib/MessageTypes.ts). However, the code at lines 48-49 sends this message when an admin/moderator removes a user in an invited state (indicated by options.byUser being present), not when the user themselves rejects the invitation.

The commit history shows that 'uir' was previously used in federation code where a user actively rejected an invite. Moving this to the common removeUserFromRoom function conflates two different scenarios:

  • User-initiated rejection (federation workflow)
  • Admin-initiated removal of invited user (your new code path)

The translation displays "User rejected invitation to room," which suggests the user took the action, creating confusion in user-facing messages when an admin revokes an invite.

Recommended actions:

  1. Define a distinct message type for admin invite revocation (e.g., 'uir-revoked', 'air', or 'invite-revoked'), or
  2. If intentionally reusing 'uir' for both scenarios, update the message type definition and translation to reflect both user rejection and admin revocation.
ee/packages/federation-matrix/src/events/member.ts (3)

113-158: LGTM! Proper invite acceptance flow.

The join handler correctly distinguishes between direct joins (no prior invite) and invite acceptances, with appropriate subscription state updates to clear invite metadata and activate the subscription.


160-177: LGTM! Clean leave implementation.

The leave handler appropriately delegates to the Room.removeUserFromRoom service method, which handles all necessary cleanup including subscription removal and user count adjustments.


182-197: LGTM! Clear event dispatching.

The switch-based dispatcher cleanly routes membership events to their respective handlers with appropriate logging for unknown membership types.

ee/packages/federation-matrix/src/FederationMatrix.ts (1)

929-934: Add explicit handling for invalid action values.

The method uses separate if statements for 'accept' and 'reject' actions. If an invalid action value is passed, the method silently does nothing, which could mask bugs.

Apply this diff to use if/else and explicitly handle invalid actions:

 if (action === 'accept') {
     await federationSDK.acceptInvite(subscription.federation?.inviteEventId, matrixUserId);
-}
-if (action === 'reject') {
+} else if (action === 'reject') {
     await federationSDK.rejectInvite(subscription.federation?.inviteEventId, matrixUserId);
+} else {
+    throw new Error(`Invalid action: ${action}`);
 }
⛔ Skipped due to learnings
Learnt from: ricardogarim
Repo: RocketChat/Rocket.Chat PR: 37377
File: apps/meteor/ee/server/hooks/federation/index.ts:86-88
Timestamp: 2025-11-04T16:49:19.107Z
Learning: In Rocket.Chat's federation system (apps/meteor/ee/server/hooks/federation/), permission checks follow two distinct patterns: (1) User-initiated federation actions (creating rooms, adding users to federated rooms, joining from invites) should throw MeteorError to inform users they lack 'access-federation' permission. (2) Remote server-initiated federation events should silently skip/ignore when users lack permission. The beforeAddUserToRoom hook only executes for local user-initiated actions, so throwing an error there is correct. Remote federation events are handled separately by the federation Matrix package with silent skipping logic.

@ricardogarim ricardogarim marked this pull request as draft November 17, 2025 20:21
@ricardogarim ricardogarim force-pushed the feat/invites branch 4 times, most recently from 4776e08 to 3e950a0 Compare November 19, 2025 02:10
@ricardogarim ricardogarim marked this pull request as ready for review November 19, 2025 02:11
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

♻️ Duplicate comments (1)
ee/packages/federation-matrix/src/events/member.ts (1)

17-21: Validate inviter username before usage.

The code uses inviterUser.username on lines 62 and 71 without validation. Since IUser.username is optional, this could lead to:

  • Line 62: Unsafe cast to UserID if username is undefined
  • Line 71: Storing undefined as inviterUsername in federation metadata

Add validation after line 21:

 const inviterUser = await getOrCreateFederatedUser(senderId as UserID);
 if (!inviterUser) {
     logger.error(`Failed to get or create inviter user: ${senderId}`);
     return;
 }
+if (!inviterUser.username) {
+    logger.error(`Inviter user ${inviterUser._id} has no username`);
+    return;
+}

Note: This issue was flagged in a previous review but appears unresolved.

Also applies to: 57-63, 69-72

🧹 Nitpick comments (4)
apps/meteor/app/lib/server/functions/acceptRoomInvite.ts (1)

9-20: Guard against mismatched room/subscription/user triplets

The function assumes room, subscription, and user are consistent (same room and user). To make this helper safer against accidental misuse by future callers, consider asserting:

  • subscription.rid === room._id
  • subscription.u._id === user._id

before proceeding, and throwing a Meteor.Error if they do not match. This keeps the trust boundary clear while reusing the helper in other call sites.

apps/meteor/app/lib/server/methods/addUsersToRoom.ts (1)

110-121: Make inviteResult[0] handling robust against empty results

The new federation invite path is wired correctly, but inviteResult[0] assumes that inviteUsersToRoom always returns at least one element:

const inviteResult = await FederationMatrix.inviteUsersToRoom(...);
inviteOptions = {
  invited: true,
  federation: {
    inviteEventId: inviteResult[0].event_id,
    inviterUsername: user.username,
  },
};

Today this holds when called from local user flows, but inviteUsersToRoom can return an empty array if the caller ever passes a combination that leads to usersToInvite.length === 0. To future‑proof this helper, consider guarding the assignment:

- const inviteResult = await FederationMatrix.inviteUsersToRoom(room, [newUser.username], user);
- inviteOptions = {
-   invited: true,
-   federation: {
-     inviteEventId: inviteResult[0].event_id,
-     inviterUsername: user.username,
-   },
- };
+ const inviteResult = await FederationMatrix.inviteUsersToRoom(room, [newUser.username], user);
+ if (inviteResult.length > 0) {
+   inviteOptions = {
+     invited: true,
+     federation: {
+       inviteEventId: inviteResult[0].event_id,
+       inviterUsername: user.username,
+     },
+   };
+ }

This keeps the invite metadata optional but avoids potential undefined access if the federation layer changes behavior later.

Since this depends on FederationMatrix.inviteUsersToRoom’s contract, please confirm its “no‑op” behavior and whether it can ever legitimately return [] for this call pattern.

Also applies to: 123-124

apps/meteor/app/lib/server/functions/addUserToRoom.ts (1)

134-137: Consider tightening inviter type to require username.

The new UI message path on line 134 uses inviter.username on line 136 without validation. While this follows the existing pattern (line 129), a past reviewer (ggazzo) suggested "it should be impossible to have an inviter without username, what about fix the type?"

Consider updating the inviter parameter type from Pick<IUser, '_id' | 'username'> to Pick<IUser, '_id'> & Required<Pick<IUser, 'username'>> to enforce username at the type level.

Note: This applies to the entire function, not just the new code.

ee/packages/federation-matrix/src/events/helpers.ts (1)

86-93: Consider returning null instead of empty string on error.

The extractDomainFromId function returns an empty string on error (line 91), which could mask failures. Callers might not distinguish between "no domain" and "error extracting domain."

Consider returning null or the original matrixId on error for clearer error signaling:

-export function extractDomainFromId(matrixId: string): string {
+export function extractDomainFromId(matrixId: string): string | null {
     try {
         return extractDomainFromMatrixUserId(matrixId);
     } catch (error) {
         logger.error(`Error extracting domain from Matrix ID ${matrixId}:`, error);
-        return '';
+        return null;
     }
 }
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

Disabled knowledge base sources:

  • Jira integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between 279d97b and 3e950a0.

📒 Files selected for processing (18)
  • apps/meteor/app/api/server/v1/rooms.ts (3 hunks)
  • apps/meteor/app/lib/lib/MessageTypes.ts (1 hunks)
  • apps/meteor/app/lib/server/functions/acceptRoomInvite.ts (1 hunks)
  • apps/meteor/app/lib/server/functions/addUserToRoom.ts (3 hunks)
  • apps/meteor/app/lib/server/functions/removeUserFromRoom.ts (2 hunks)
  • apps/meteor/app/lib/server/methods/addUsersToRoom.ts (2 hunks)
  • apps/meteor/ee/server/hooks/federation/index.ts (1 hunks)
  • apps/meteor/lib/publishFields.ts (1 hunks)
  • apps/meteor/server/lib/dataExport/exportRoomMessagesToFile.ts (1 hunks)
  • apps/meteor/server/lib/findUsersOfRoomOrderedByRole.ts (1 hunks)
  • apps/meteor/server/modules/watchers/watchers.module.ts (1 hunks)
  • apps/meteor/server/services/room/service.ts (2 hunks)
  • ee/packages/federation-matrix/src/FederationMatrix.ts (4 hunks)
  • ee/packages/federation-matrix/src/api/_matrix/invite.ts (3 hunks)
  • ee/packages/federation-matrix/src/events/helpers.ts (1 hunks)
  • ee/packages/federation-matrix/src/events/member.ts (1 hunks)
  • ee/packages/federation-matrix/src/events/room.ts (1 hunks)
  • ee/packages/federation-matrix/src/helpers/message.parsers.ts (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (5)
  • apps/meteor/server/lib/dataExport/exportRoomMessagesToFile.ts
  • apps/meteor/lib/publishFields.ts
  • apps/meteor/app/lib/lib/MessageTypes.ts
  • apps/meteor/server/modules/watchers/watchers.module.ts
  • apps/meteor/app/api/server/v1/rooms.ts
🧰 Additional context used
🧠 Learnings (11)
📓 Common learnings
Learnt from: ricardogarim
Repo: RocketChat/Rocket.Chat PR: 37377
File: apps/meteor/ee/server/hooks/federation/index.ts:86-88
Timestamp: 2025-11-04T16:49:19.107Z
Learning: In Rocket.Chat's federation system (apps/meteor/ee/server/hooks/federation/), permission checks follow two distinct patterns: (1) User-initiated federation actions (creating rooms, adding users to federated rooms, joining from invites) should throw MeteorError to inform users they lack 'access-federation' permission. (2) Remote server-initiated federation events should silently skip/ignore when users lack permission. The beforeAddUserToRoom hook only executes for local user-initiated actions, so throwing an error there is correct. Remote federation events are handled separately by the federation Matrix package with silent skipping logic.
Learnt from: ricardogarim
Repo: RocketChat/Rocket.Chat PR: 37205
File: ee/packages/federation-matrix/src/FederationMatrix.ts:296-301
Timestamp: 2025-10-28T16:53:42.761Z
Learning: In the Rocket.Chat federation-matrix integration (ee/packages/federation-matrix/), the createRoom method from rocket.chat/federation-sdk will support a 4-argument signature (userId, roomName, visibility, displayName) in newer versions. Code using this 4-argument call is forward-compatible with planned library updates and should not be flagged as an error.
Learnt from: ricardogarim
Repo: RocketChat/Rocket.Chat PR: 37205
File: ee/packages/federation-matrix/src/FederationMatrix.ts:296-301
Timestamp: 2025-10-28T16:53:42.761Z
Learning: In the Rocket.Chat federation-matrix integration (ee/packages/federation-matrix/), the createRoom method from rocket.chat/federation-sdk will support a 4-argument signature (userId, roomName, visibility, displayName) in newer versions. Code using this 4-argument call is forward-compatible with planned library updates and should not be flagged as an error.
Learnt from: MartinSchoeler
Repo: RocketChat/Rocket.Chat PR: 37408
File: apps/meteor/client/views/admin/ABAC/useRoomAttributeOptions.tsx:53-69
Timestamp: 2025-11-10T19:06:20.146Z
Learning: In the Rocket.Chat repository, do not provide suggestions or recommendations about code sections marked with TODO comments. The maintainers have already identified these as future work and external reviewers lack the full context about implementation plans and timing.
📚 Learning: 2025-10-28T16:53:42.761Z
Learnt from: ricardogarim
Repo: RocketChat/Rocket.Chat PR: 37205
File: ee/packages/federation-matrix/src/FederationMatrix.ts:296-301
Timestamp: 2025-10-28T16:53:42.761Z
Learning: In the Rocket.Chat federation-matrix integration (ee/packages/federation-matrix/), the createRoom method from rocket.chat/federation-sdk will support a 4-argument signature (userId, roomName, visibility, displayName) in newer versions. Code using this 4-argument call is forward-compatible with planned library updates and should not be flagged as an error.

Applied to files:

  • apps/meteor/app/lib/server/functions/acceptRoomInvite.ts
  • apps/meteor/server/lib/findUsersOfRoomOrderedByRole.ts
  • ee/packages/federation-matrix/src/events/room.ts
  • ee/packages/federation-matrix/src/events/member.ts
  • apps/meteor/ee/server/hooks/federation/index.ts
  • apps/meteor/app/lib/server/functions/removeUserFromRoom.ts
  • apps/meteor/app/lib/server/methods/addUsersToRoom.ts
  • ee/packages/federation-matrix/src/api/_matrix/invite.ts
  • apps/meteor/server/services/room/service.ts
  • ee/packages/federation-matrix/src/FederationMatrix.ts
  • ee/packages/federation-matrix/src/events/helpers.ts
  • apps/meteor/app/lib/server/functions/addUserToRoom.ts
📚 Learning: 2025-09-25T09:59:26.461Z
Learnt from: Dnouv
Repo: RocketChat/Rocket.Chat PR: 37057
File: packages/apps-engine/src/definition/accessors/IUserRead.ts:23-27
Timestamp: 2025-09-25T09:59:26.461Z
Learning: AppUserBridge.getUserRoomIds in apps/meteor/app/apps/server/bridges/users.ts always returns an array of strings (mapping subscription documents to room IDs), never undefined, even when user has no room subscriptions.

Applied to files:

  • apps/meteor/app/lib/server/functions/acceptRoomInvite.ts
  • apps/meteor/server/lib/findUsersOfRoomOrderedByRole.ts
  • ee/packages/federation-matrix/src/events/room.ts
  • ee/packages/federation-matrix/src/events/member.ts
  • apps/meteor/app/lib/server/functions/removeUserFromRoom.ts
  • apps/meteor/app/lib/server/methods/addUsersToRoom.ts
  • apps/meteor/server/services/room/service.ts
  • ee/packages/federation-matrix/src/FederationMatrix.ts
  • ee/packages/federation-matrix/src/events/helpers.ts
  • apps/meteor/app/lib/server/functions/addUserToRoom.ts
📚 Learning: 2025-09-25T09:59:26.461Z
Learnt from: Dnouv
Repo: RocketChat/Rocket.Chat PR: 37057
File: packages/apps-engine/src/definition/accessors/IUserRead.ts:23-27
Timestamp: 2025-09-25T09:59:26.461Z
Learning: AppUserBridge.getUserRoomIds in apps/meteor/app/apps/server/bridges/users.ts always returns an array of strings by mapping subscription documents to room IDs, never undefined, even when user has no room subscriptions.

Applied to files:

  • apps/meteor/app/lib/server/functions/acceptRoomInvite.ts
  • apps/meteor/server/lib/findUsersOfRoomOrderedByRole.ts
  • ee/packages/federation-matrix/src/events/room.ts
  • ee/packages/federation-matrix/src/events/member.ts
  • apps/meteor/app/lib/server/functions/removeUserFromRoom.ts
  • apps/meteor/app/lib/server/methods/addUsersToRoom.ts
  • apps/meteor/server/services/room/service.ts
  • ee/packages/federation-matrix/src/FederationMatrix.ts
  • ee/packages/federation-matrix/src/events/helpers.ts
  • apps/meteor/app/lib/server/functions/addUserToRoom.ts
📚 Learning: 2025-11-04T16:49:19.107Z
Learnt from: ricardogarim
Repo: RocketChat/Rocket.Chat PR: 37377
File: apps/meteor/ee/server/hooks/federation/index.ts:86-88
Timestamp: 2025-11-04T16:49:19.107Z
Learning: In Rocket.Chat's federation system (apps/meteor/ee/server/hooks/federation/), permission checks follow two distinct patterns: (1) User-initiated federation actions (creating rooms, adding users to federated rooms, joining from invites) should throw MeteorError to inform users they lack 'access-federation' permission. (2) Remote server-initiated federation events should silently skip/ignore when users lack permission. The beforeAddUserToRoom hook only executes for local user-initiated actions, so throwing an error there is correct. Remote federation events are handled separately by the federation Matrix package with silent skipping logic.

Applied to files:

  • apps/meteor/app/lib/server/functions/acceptRoomInvite.ts
  • ee/packages/federation-matrix/src/events/room.ts
  • ee/packages/federation-matrix/src/events/member.ts
  • apps/meteor/ee/server/hooks/federation/index.ts
  • apps/meteor/app/lib/server/functions/removeUserFromRoom.ts
  • apps/meteor/app/lib/server/methods/addUsersToRoom.ts
  • ee/packages/federation-matrix/src/api/_matrix/invite.ts
  • apps/meteor/server/services/room/service.ts
  • ee/packages/federation-matrix/src/FederationMatrix.ts
  • ee/packages/federation-matrix/src/events/helpers.ts
  • apps/meteor/app/lib/server/functions/addUserToRoom.ts
📚 Learning: 2025-09-19T15:15:04.642Z
Learnt from: rodrigok
Repo: RocketChat/Rocket.Chat PR: 36991
File: apps/meteor/server/services/federation/infrastructure/rocket-chat/adapters/Settings.ts:219-221
Timestamp: 2025-09-19T15:15:04.642Z
Learning: The Federation_Matrix_homeserver_domain setting in apps/meteor/server/services/federation/infrastructure/rocket-chat/adapters/Settings.ts is part of the old federation system and is being deprecated/removed, so configuration issues with this setting should not be flagged for improvement.

Applied to files:

  • ee/packages/federation-matrix/src/events/room.ts
  • ee/packages/federation-matrix/src/events/member.ts
  • apps/meteor/ee/server/hooks/federation/index.ts
  • apps/meteor/app/lib/server/methods/addUsersToRoom.ts
  • ee/packages/federation-matrix/src/api/_matrix/invite.ts
  • ee/packages/federation-matrix/src/FederationMatrix.ts
  • ee/packages/federation-matrix/src/events/helpers.ts
  • apps/meteor/app/lib/server/functions/addUserToRoom.ts
📚 Learning: 2025-11-10T19:06:20.146Z
Learnt from: MartinSchoeler
Repo: RocketChat/Rocket.Chat PR: 37408
File: apps/meteor/client/views/admin/ABAC/useRoomAttributeOptions.tsx:53-69
Timestamp: 2025-11-10T19:06:20.146Z
Learning: In the Rocket.Chat repository, do not provide suggestions or recommendations about code sections marked with TODO comments. The maintainers have already identified these as future work and external reviewers lack the full context about implementation plans and timing.

Applied to files:

  • ee/packages/federation-matrix/src/events/member.ts
📚 Learning: 2025-09-25T09:59:26.461Z
Learnt from: Dnouv
Repo: RocketChat/Rocket.Chat PR: 37057
File: packages/apps-engine/src/definition/accessors/IUserRead.ts:23-27
Timestamp: 2025-09-25T09:59:26.461Z
Learning: UserBridge.doGetUserRoomIds in packages/apps-engine/src/server/bridges/UserBridge.ts has a bug where it implicitly returns undefined when the app lacks read permission (missing return statement in the else case of the permission check).

Applied to files:

  • ee/packages/federation-matrix/src/events/member.ts
  • apps/meteor/app/lib/server/functions/removeUserFromRoom.ts
  • apps/meteor/app/lib/server/functions/addUserToRoom.ts
📚 Learning: 2025-09-16T13:33:49.237Z
Learnt from: cardoso
Repo: RocketChat/Rocket.Chat PR: 36890
File: apps/meteor/tests/e2e/e2e-encryption/e2ee-otr.spec.ts:21-26
Timestamp: 2025-09-16T13:33:49.237Z
Learning: The im.delete API endpoint accepts either a `roomId` parameter (requiring the actual DM room _id) or a `username` parameter (for the DM partner's username). Constructing slug-like identifiers like `user2${Users.userE2EE.data.username}` doesn't work for this endpoint.

Applied to files:

  • ee/packages/federation-matrix/src/events/member.ts
📚 Learning: 2025-11-05T21:04:35.787Z
Learnt from: sampaiodiego
Repo: RocketChat/Rocket.Chat PR: 37357
File: ee/packages/federation-matrix/src/setup.ts:103-120
Timestamp: 2025-11-05T21:04:35.787Z
Learning: In Rocket.Chat's federation-matrix setup (ee/packages/federation-matrix/src/setup.ts and apps/meteor/ee/server/startup/federation.ts), configureFederationMatrixSettings does not need to be called before setupFederationMatrix. The SDK's init() establishes infrastructure (database, event handlers, APIs) first, and the configuration can be applied later via settings watchers before actual federation events are processed. The config only matters when events actually occur, at which point all infrastructure is already configured.

Applied to files:

  • ee/packages/federation-matrix/src/events/member.ts
  • apps/meteor/ee/server/hooks/federation/index.ts
  • apps/meteor/app/lib/server/methods/addUsersToRoom.ts
  • ee/packages/federation-matrix/src/api/_matrix/invite.ts
  • ee/packages/federation-matrix/src/FederationMatrix.ts
  • ee/packages/federation-matrix/src/events/helpers.ts
📚 Learning: 2025-10-01T12:20:13.147Z
Learnt from: sampaiodiego
Repo: RocketChat/Rocket.Chat PR: 37110
File: apps/meteor/ee/server/startup/federation.ts:17-21
Timestamp: 2025-10-01T12:20:13.147Z
Learning: In Rocket.Chat's StreamerCentral broadcast for 'notify-room' events with 'user-activity', the `activity` argument is a string (e.g., 'user-typing') when a user starts typing and an empty array when the user stops typing.

Applied to files:

  • ee/packages/federation-matrix/src/FederationMatrix.ts
🧬 Code graph analysis (7)
apps/meteor/app/lib/server/functions/acceptRoomInvite.ts (6)
apps/meteor/server/services/room/service.ts (1)
  • acceptRoomInvite (86-88)
packages/core-typings/src/IRoom.ts (1)
  • IRoom (21-95)
packages/core-typings/src/ISubscription.ts (1)
  • ISubscription (10-81)
packages/core-typings/src/IUser.ts (1)
  • IUser (186-255)
apps/meteor/lib/callbacks.ts (1)
  • callbacks (252-260)
apps/meteor/app/lib/server/lib/notifyListener.ts (1)
  • notifyOnSubscriptionChangedById (535-544)
ee/packages/federation-matrix/src/events/member.ts (2)
ee/packages/federation-matrix/src/FederationMatrix.ts (1)
  • handleInvite (916-950)
ee/packages/federation-matrix/src/events/helpers.ts (2)
  • getOrCreateFederatedUser (12-48)
  • getOrCreateFederatedRoom (50-84)
apps/meteor/app/lib/server/methods/addUsersToRoom.ts (4)
packages/core-typings/src/IRoom.ts (1)
  • isRoomNativeFederated (124-125)
ee/packages/federation-matrix/src/FederationMatrix.ts (1)
  • FederationMatrix (144-951)
packages/core-services/src/index.ts (1)
  • FederationMatrix (199-199)
apps/meteor/app/lib/server/functions/addUserToRoom.ts (1)
  • addUserToRoom (22-173)
apps/meteor/server/services/room/service.ts (2)
packages/core-typings/src/ISubscription.ts (1)
  • ISubscription (10-81)
apps/meteor/app/lib/server/functions/acceptRoomInvite.ts (1)
  • acceptRoomInvite (9-31)
ee/packages/federation-matrix/src/FederationMatrix.ts (3)
packages/core-typings/src/IRoom.ts (3)
  • IRoomNativeFederated (114-120)
  • RoomID (12-12)
  • isRoomNativeFederated (124-125)
packages/core-typings/src/IUser.ts (2)
  • IUser (186-255)
  • isUserNativeFederated (276-277)
packages/core-typings/src/ISubscription.ts (1)
  • ISubscription (10-81)
ee/packages/federation-matrix/src/events/helpers.ts (4)
packages/core-typings/src/IUser.ts (1)
  • IUser (186-255)
ee/packages/federation-matrix/src/FederationMatrix.ts (3)
  • getUsernameServername (80-92)
  • createOrUpdateFederatedUser (99-140)
  • extractDomainFromMatrixUserId (67-73)
packages/core-typings/src/IRoom.ts (2)
  • RoomID (12-12)
  • IRoom (21-95)
packages/core-services/src/index.ts (1)
  • Room (169-169)
apps/meteor/app/lib/server/functions/addUserToRoom.ts (1)
packages/core-services/src/index.ts (1)
  • Message (184-184)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (3)
  • GitHub Check: 📦 Build Packages
  • GitHub Check: CodeQL-Build
  • GitHub Check: CodeQL-Build
🔇 Additional comments (20)
ee/packages/federation-matrix/src/helpers/message.parsers.ts (1)

5-5: MatrixMessageContent now correctly mirrors the federation SDK event content type

Switching MatrixMessageContent to HomeserverEventSignatures['homeserver.matrix.message']['event']['content'] & { format?: string } aligns the local type with the SDK’s Matrix event shape and keeps createReplyContent strongly typed against the actual event.content payload. The extra & { format?: string } is safe (and covers cases where format is not present on the SDK type) and doesn’t alter runtime behavior.

apps/meteor/app/lib/server/functions/acceptRoomInvite.ts (1)

22-30: Join flow wiring looks consistent with existing patterns

Using beforeJoinRoom/afterJoinRoom callbacks, updating the subscription state, broadcasting via notifyOnSubscriptionChangedById, and emitting a 'uj' system message matches the existing room-join semantics, which should keep invite acceptance aligned with normal joins.

apps/meteor/ee/server/hooks/federation/index.ts (1)

1-1: Imports are consistent with downstream usage

The FederationMatrix and beforeAddUsersToRoom imports line up with the usages later in this file (create room, message propagation, and ensuring federated users exist locally). The wiring here looks correct and keeps the federation hooks centralized.

Also applies to: 8-8

apps/meteor/app/lib/server/functions/removeUserFromRoom.ts (1)

36-37: Nice separation of “reject invite” from normal leave/kick flows

Including invited in the projection and adding the subscription.invited branch with the 'uir' system message clearly distinguishes:

  • Kick / removal by someone else (options.byUser present),
  • Explicit invite rejection (subscription.invited === true),
  • Normal user leave (ul/ult).

This should make invite rejection UX much clearer, as long as the reject paths call removeUserFromRoom without options.byUser. The implementation itself looks solid.

Please double‑check that all “reject invite” call sites invoke removeUserFromRoom without options.byUser, so they hit the new 'uir' branch instead of the generic leave/kick messages.

Also applies to: 51-57

apps/meteor/app/lib/server/methods/addUsersToRoom.ts (1)

1-1: Federated invite integration into addUsersToRoom looks correct; ensure access-federation permission is still enforced elsewhere

The method now:

  • Validates federated usernames upfront and rejects them for non‑federated rooms.
  • Runs beforeAddUsersToRoom once for all usernames, passing inviter: user.
  • For users not yet subscribed:
    • Optionally calls FederationMatrix.inviteUsersToRoom when the room is native‑federated and the user has a username.
    • Threads invited and federation metadata through to addUserToRoom, so subscription/system messages can reflect the invite.
  • For already‑subscribed users with username, emits the ephemeral “already in here” message via api.broadcast.

This is a good consolidation of the invite path into the existing add‑user flow.

Given the prior pattern in federation hooks (user‑initiated federation actions should enforce access-federation and fail loudly, while remote events should be silent when lacking permission – based on learnings), just make sure that this method (or a beforeAddUsersToRoom subscriber) still enforces access-federation for federated rooms when appropriate.

If access-federation enforcement has been moved to a shared callback (e.g., in beforeAddUserToRoom.ts), please double‑check that it still runs for this method’s code path, and not for remote homeserver‑initiated events.

Also applies to: 88-99, 101-109, 126-136

apps/meteor/server/services/room/service.ts (1)

86-88: LGTM! Clean delegation pattern for invite acceptance.

The new method follows the established service pattern by delegating to the imported acceptRoomInvite function. The signature is type-safe and consistent with other methods in the class.

ee/packages/federation-matrix/src/api/_matrix/invite.ts (3)

136-172: LGTM! Validate local-only invite acceptance.

The acceptInvite function correctly validates that both inviter and invitee are local users (not native federated) when processing invites to federated rooms, which aligns with the comment stating this is for "inside rocket chat we invite users inside rockechat."


220-230: LGTM! Proper federation permission check added.

The permission check correctly validates access-federation before processing the invite, and logs appropriately when access is denied. This aligns with the federation permission patterns.

Based on learnings


232-261: LGTM! Comprehensive error handling for invite processing.

The error handling correctly distinguishes between NotAllowedError (403) and general errors (500), providing appropriate error codes and messages for each case.

ee/packages/federation-matrix/src/events/member.ts (3)

75-98: LGTM! Clean join handling with proper validation.

The handleJoin function correctly validates all prerequisites (user, room, subscription) before calling Room.acceptRoomInvite. Error handling distinguishes between critical errors (missing room) and expected conditions (missing subscription for logging).


100-116: LGTM! Straightforward leave handling.

The handleLeave function correctly validates user and room existence before removing the user. The implementation is clean and follows consistent error logging patterns.


118-140: LGTM! Clean event dispatcher with proper error handling.

The membership event dispatcher correctly routes to specialized handlers based on membership type, with appropriate error handling and logging. The eventId is passed only to handleInvite where it's needed for federation metadata.

apps/meteor/app/lib/server/functions/addUserToRoom.ts (2)

30-40: LGTM! Clean parameter extension for federation support.

The optional invited and federation parameters are well-typed and don't break existing callers. The federation object structure clearly captures the invite metadata needed for federation tracking.


109-110: LGTM! Clean conditional inclusion of federation fields.

The subscription creation correctly uses conditional spread operators to include invited and federation fields only when present, keeping the subscription document clean.

ee/packages/federation-matrix/src/FederationMatrix.ts (3)

550-589: LGTM! Enhanced invite handling with proper user filtering.

The updated inviteUsersToRoom method correctly filters users based on whether the inviter is native federated, preventing unnecessary processing. The new return type provides useful invite event context to callers.


859-862: LGTM! Important subscription verification added.

The subscription check on lines 859-862 correctly verifies the user has joined the room before sending typing notifications. This prevents inappropriate typing notifications for users who haven't actually joined the room yet.


916-950: LGTM! Proper validation order for invite handling.

The handleInvite method correctly validates the subscription, user, and username (line 937-939) before constructing the matrixUserId (line 942). All validations are in the proper order to prevent errors.

Note: A previous review comment suggested moving username validation before matrixUserId construction, but the current code already has the correct order.

ee/packages/federation-matrix/src/events/helpers.ts (3)

12-48: LGTM! Robust federated user resolution.

The getOrCreateFederatedUser helper correctly distinguishes between local and remote users, only auto-creating remote federated users. Local users that don't exist trigger a warning and return null, which is the correct behavior.


50-84: LGTM! Clean federated room creation helper.

The getOrCreateFederatedRoom helper follows a clean lookup-or-create pattern and correctly uses the Room service for creation. Federation metadata and room properties are properly configured.


95-103: LGTM! Safe username extraction with fallback.

The extractUsernameFromMatrixId function safely extracts the username and returns the original matrixId as a fallback on error, which is a reasonable approach.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

♻️ Duplicate comments (3)
apps/meteor/app/lib/server/functions/addUserToRoom.ts (1)

131-134: Validate inviter username before using it in system message.

The ui system message path uses inviter.username without checking if it's defined. Since username is optional on IUser, this could result in an undefined value being stored in the message.

Based on past review comments.

Apply this diff to add validation:

 		} else if (status === 'INVITED') {
+			if (!inviter.username) {
+				throw new Meteor.Error('error-invalid-inviter', 'Cannot create invite message without inviter username');
+			}
 			await Message.saveSystemMessage('ui', rid, userToBeAdded.username, userToBeAdded, {
 				u: { _id: inviter._id, username: inviter.username },
 			});
apps/meteor/app/lib/server/methods/addUsersToRoom.ts (1)

110-120: Validate inviter username before using it in invite options.

Line 116 uses user.username without checking if it's defined. Since username is optional on IUser, this could result in undefined inviterUsername being passed to the invite flow.

Based on past review comments.

Apply this diff to add validation:

 			let inviteOptions: { status?: SubscriptionStatus; inviterUsername?: string } = {};
 
 			if (isRoomNativeFederated(room) && user && newUser.username) {
+				if (!user.username) {
+					throw new Meteor.Error('error-invalid-inviter', 'Cannot invite to federated room without inviter username');
+				}
 				await FederationMatrix.inviteUsersToRoom(room, [newUser.username], user);
 				inviteOptions = {
 					status: 'INVITED',
 					inviterUsername: user.username,
 				};
 			}
ee/packages/federation-matrix/src/events/member.ts (1)

54-69: Validate inviter username before using it.

Lines 59 and 68 use inviterUser.username without checking if it's defined. Since username is optional on IUser, the cast to UserID on line 59 is unsafe, and line 68 could store undefined as inviterUsername.

Based on past review comments.

Apply this diff to add validation after line 18:

 	const inviterUser = await getOrCreateFederatedUser(senderId as UserID);
 	if (!inviterUser) {
 		logger.error(`Failed to get or create inviter user: ${senderId}`);
 		return;
 	}
+	if (!inviterUser.username) {
+		logger.error(`Inviter user ${inviterUser._id} has no username`);
+		return;
+	}
🧹 Nitpick comments (3)
ee/packages/federation-matrix/src/FederationMatrix.ts (3)

842-867: LGTM with minor optional refinement.

The enhanced validation logic properly ensures the user has joined the room before sending typing notifications, preventing potential errors.

Optional refinement: Line 859 uses localUser?._id with optional chaining, but this is unnecessary since lines 855-857 already ensure localUser exists. You can simplify to localUser._id.

-		const hasUserJoinedRoom = await Subscriptions.findOneByRoomIdAndUserId(room._id, localUser?._id, { projection: { _id: 1 } });
+		const hasUserJoinedRoom = await Subscriptions.findOneByRoomIdAndUserId(room._id, localUser._id, { projection: { _id: 1 } });

939-944: Conditional username validation needed for native federated users.

The username validation at lines 939-941 occurs before constructing matrixUserId (good!), but it should only be required when the user is NOT a native federated user. Native federated users use user.federation.mui directly and may not have a username set.

Apply this diff to make username validation conditional:

 const user = await Users.findOneById(userId);
 if (!user) {
     throw new Error('User not found');
 }
 
-if (!user.username) {
-    throw new Error('User username not found');
-}
-
 // TODO: should use common function to get matrix user ID
 const matrixUserId = isUserNativeFederated(user) ? user.federation.mui : `@${user.username}:${this.serverName}`;
+
+if (!isUserNativeFederated(user) && !user.username) {
+    throw new Error('User username not found');
+}

Based on learnings, this aligns with federation patterns where native federated users have different identifier requirements.


943-943: Address or track the TODO comment.

The TODO suggests creating a common function to get the matrix user ID, which would improve code reusability since this pattern appears in multiple places (lines 466, 557, 610, 650, 699, 714, 747, 780, 795, 820, 864, 944).

Would you like me to open a new issue to track the creation of a common helper function for retrieving matrix user IDs?

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

Disabled knowledge base sources:

  • Jira integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between 3e950a0 and f37c9db.

📒 Files selected for processing (13)
  • apps/meteor/app/lib/server/functions/acceptRoomInvite.ts (1 hunks)
  • apps/meteor/app/lib/server/functions/addUserToRoom.ts (4 hunks)
  • apps/meteor/app/lib/server/functions/removeUserFromRoom.ts (2 hunks)
  • apps/meteor/app/lib/server/methods/addUsersToRoom.ts (2 hunks)
  • apps/meteor/lib/publishFields.ts (1 hunks)
  • apps/meteor/server/lib/findUsersOfRoomOrderedByRole.ts (1 hunks)
  • apps/meteor/server/modules/watchers/watchers.module.ts (1 hunks)
  • ee/packages/federation-matrix/src/FederationMatrix.ts (4 hunks)
  • ee/packages/federation-matrix/src/events/member.ts (1 hunks)
  • packages/core-services/src/types/IRoomService.ts (2 hunks)
  • packages/core-typings/src/IInquiry.ts (1 hunks)
  • packages/core-typings/src/ISubscription.ts (2 hunks)
  • packages/models/src/models/Subscriptions.ts (2 hunks)
🚧 Files skipped from review as they are similar to previous changes (4)
  • apps/meteor/app/lib/server/functions/removeUserFromRoom.ts
  • packages/core-typings/src/ISubscription.ts
  • apps/meteor/server/lib/findUsersOfRoomOrderedByRole.ts
  • apps/meteor/app/lib/server/functions/acceptRoomInvite.ts
🧰 Additional context used
📓 Path-based instructions (1)
**/*.{ts,tsx,js}

📄 CodeRabbit inference engine (.cursor/rules/playwright.mdc)

**/*.{ts,tsx,js}: Write concise, technical TypeScript/JavaScript with accurate typing in Playwright tests
Avoid code comments in the implementation

Files:

  • packages/models/src/models/Subscriptions.ts
  • packages/core-typings/src/IInquiry.ts
  • apps/meteor/app/lib/server/functions/addUserToRoom.ts
  • ee/packages/federation-matrix/src/FederationMatrix.ts
  • packages/core-services/src/types/IRoomService.ts
  • ee/packages/federation-matrix/src/events/member.ts
  • apps/meteor/lib/publishFields.ts
  • apps/meteor/server/modules/watchers/watchers.module.ts
  • apps/meteor/app/lib/server/methods/addUsersToRoom.ts
🧠 Learnings (12)
📓 Common learnings
Learnt from: ricardogarim
Repo: RocketChat/Rocket.Chat PR: 37377
File: apps/meteor/ee/server/hooks/federation/index.ts:86-88
Timestamp: 2025-11-04T16:49:19.107Z
Learning: In Rocket.Chat's federation system (apps/meteor/ee/server/hooks/federation/), permission checks follow two distinct patterns: (1) User-initiated federation actions (creating rooms, adding users to federated rooms, joining from invites) should throw MeteorError to inform users they lack 'access-federation' permission. (2) Remote server-initiated federation events should silently skip/ignore when users lack permission. The beforeAddUserToRoom hook only executes for local user-initiated actions, so throwing an error there is correct. Remote federation events are handled separately by the federation Matrix package with silent skipping logic.
Learnt from: ricardogarim
Repo: RocketChat/Rocket.Chat PR: 37205
File: ee/packages/federation-matrix/src/FederationMatrix.ts:296-301
Timestamp: 2025-10-28T16:53:42.761Z
Learning: In the Rocket.Chat federation-matrix integration (ee/packages/federation-matrix/), the createRoom method from rocket.chat/federation-sdk will support a 4-argument signature (userId, roomName, visibility, displayName) in newer versions. Code using this 4-argument call is forward-compatible with planned library updates and should not be flagged as an error.
Learnt from: ricardogarim
Repo: RocketChat/Rocket.Chat PR: 37205
File: ee/packages/federation-matrix/src/FederationMatrix.ts:296-301
Timestamp: 2025-10-28T16:53:42.761Z
Learning: In the Rocket.Chat federation-matrix integration (ee/packages/federation-matrix/), the createRoom method from rocket.chat/federation-sdk will support a 4-argument signature (userId, roomName, visibility, displayName) in newer versions. Code using this 4-argument call is forward-compatible with planned library updates and should not be flagged as an error.
📚 Learning: 2025-10-28T16:53:42.761Z
Learnt from: ricardogarim
Repo: RocketChat/Rocket.Chat PR: 37205
File: ee/packages/federation-matrix/src/FederationMatrix.ts:296-301
Timestamp: 2025-10-28T16:53:42.761Z
Learning: In the Rocket.Chat federation-matrix integration (ee/packages/federation-matrix/), the createRoom method from rocket.chat/federation-sdk will support a 4-argument signature (userId, roomName, visibility, displayName) in newer versions. Code using this 4-argument call is forward-compatible with planned library updates and should not be flagged as an error.

Applied to files:

  • apps/meteor/app/lib/server/functions/addUserToRoom.ts
  • ee/packages/federation-matrix/src/FederationMatrix.ts
  • packages/core-services/src/types/IRoomService.ts
  • ee/packages/federation-matrix/src/events/member.ts
  • apps/meteor/app/lib/server/methods/addUsersToRoom.ts
📚 Learning: 2025-09-25T09:59:26.461Z
Learnt from: Dnouv
Repo: RocketChat/Rocket.Chat PR: 37057
File: packages/apps-engine/src/definition/accessors/IUserRead.ts:23-27
Timestamp: 2025-09-25T09:59:26.461Z
Learning: AppUserBridge.getUserRoomIds in apps/meteor/app/apps/server/bridges/users.ts always returns an array of strings (mapping subscription documents to room IDs), never undefined, even when user has no room subscriptions.

Applied to files:

  • apps/meteor/app/lib/server/functions/addUserToRoom.ts
  • ee/packages/federation-matrix/src/FederationMatrix.ts
  • packages/core-services/src/types/IRoomService.ts
  • ee/packages/federation-matrix/src/events/member.ts
  • apps/meteor/app/lib/server/methods/addUsersToRoom.ts
📚 Learning: 2025-09-25T09:59:26.461Z
Learnt from: Dnouv
Repo: RocketChat/Rocket.Chat PR: 37057
File: packages/apps-engine/src/definition/accessors/IUserRead.ts:23-27
Timestamp: 2025-09-25T09:59:26.461Z
Learning: AppUserBridge.getUserRoomIds in apps/meteor/app/apps/server/bridges/users.ts always returns an array of strings by mapping subscription documents to room IDs, never undefined, even when user has no room subscriptions.

Applied to files:

  • apps/meteor/app/lib/server/functions/addUserToRoom.ts
  • ee/packages/federation-matrix/src/FederationMatrix.ts
  • packages/core-services/src/types/IRoomService.ts
  • ee/packages/federation-matrix/src/events/member.ts
  • apps/meteor/app/lib/server/methods/addUsersToRoom.ts
📚 Learning: 2025-11-04T16:49:19.107Z
Learnt from: ricardogarim
Repo: RocketChat/Rocket.Chat PR: 37377
File: apps/meteor/ee/server/hooks/federation/index.ts:86-88
Timestamp: 2025-11-04T16:49:19.107Z
Learning: In Rocket.Chat's federation system (apps/meteor/ee/server/hooks/federation/), permission checks follow two distinct patterns: (1) User-initiated federation actions (creating rooms, adding users to federated rooms, joining from invites) should throw MeteorError to inform users they lack 'access-federation' permission. (2) Remote server-initiated federation events should silently skip/ignore when users lack permission. The beforeAddUserToRoom hook only executes for local user-initiated actions, so throwing an error there is correct. Remote federation events are handled separately by the federation Matrix package with silent skipping logic.

Applied to files:

  • apps/meteor/app/lib/server/functions/addUserToRoom.ts
  • ee/packages/federation-matrix/src/FederationMatrix.ts
  • ee/packages/federation-matrix/src/events/member.ts
  • apps/meteor/app/lib/server/methods/addUsersToRoom.ts
📚 Learning: 2025-09-25T09:59:26.461Z
Learnt from: Dnouv
Repo: RocketChat/Rocket.Chat PR: 37057
File: packages/apps-engine/src/definition/accessors/IUserRead.ts:23-27
Timestamp: 2025-09-25T09:59:26.461Z
Learning: UserBridge.doGetUserRoomIds in packages/apps-engine/src/server/bridges/UserBridge.ts has a bug where it implicitly returns undefined when the app lacks read permission (missing return statement in the else case of the permission check).

Applied to files:

  • apps/meteor/app/lib/server/functions/addUserToRoom.ts
  • ee/packages/federation-matrix/src/events/member.ts
📚 Learning: 2025-09-19T15:15:04.642Z
Learnt from: rodrigok
Repo: RocketChat/Rocket.Chat PR: 36991
File: apps/meteor/server/services/federation/infrastructure/rocket-chat/adapters/Settings.ts:219-221
Timestamp: 2025-09-19T15:15:04.642Z
Learning: The Federation_Matrix_homeserver_domain setting in apps/meteor/server/services/federation/infrastructure/rocket-chat/adapters/Settings.ts is part of the old federation system and is being deprecated/removed, so configuration issues with this setting should not be flagged for improvement.

Applied to files:

  • ee/packages/federation-matrix/src/FederationMatrix.ts
  • ee/packages/federation-matrix/src/events/member.ts
  • apps/meteor/app/lib/server/methods/addUsersToRoom.ts
📚 Learning: 2025-11-05T21:04:35.787Z
Learnt from: sampaiodiego
Repo: RocketChat/Rocket.Chat PR: 37357
File: ee/packages/federation-matrix/src/setup.ts:103-120
Timestamp: 2025-11-05T21:04:35.787Z
Learning: In Rocket.Chat's federation-matrix setup (ee/packages/federation-matrix/src/setup.ts and apps/meteor/ee/server/startup/federation.ts), configureFederationMatrixSettings does not need to be called before setupFederationMatrix. The SDK's init() establishes infrastructure (database, event handlers, APIs) first, and the configuration can be applied later via settings watchers before actual federation events are processed. The config only matters when events actually occur, at which point all infrastructure is already configured.

Applied to files:

  • ee/packages/federation-matrix/src/FederationMatrix.ts
  • ee/packages/federation-matrix/src/events/member.ts
  • apps/meteor/app/lib/server/methods/addUsersToRoom.ts
📚 Learning: 2025-10-01T12:20:13.147Z
Learnt from: sampaiodiego
Repo: RocketChat/Rocket.Chat PR: 37110
File: apps/meteor/ee/server/startup/federation.ts:17-21
Timestamp: 2025-10-01T12:20:13.147Z
Learning: In Rocket.Chat's StreamerCentral broadcast for 'notify-room' events with 'user-activity', the `activity` argument is a string (e.g., 'user-typing') when a user starts typing and an empty array when the user stops typing.

Applied to files:

  • ee/packages/federation-matrix/src/FederationMatrix.ts
📚 Learning: 2025-11-10T19:06:20.146Z
Learnt from: MartinSchoeler
Repo: RocketChat/Rocket.Chat PR: 37408
File: apps/meteor/client/views/admin/ABAC/useRoomAttributeOptions.tsx:53-69
Timestamp: 2025-11-10T19:06:20.146Z
Learning: In the Rocket.Chat repository, do not provide suggestions or recommendations about code sections marked with TODO comments. The maintainers have already identified these as future work and external reviewers lack the full context about implementation plans and timing.

Applied to files:

  • ee/packages/federation-matrix/src/events/member.ts
📚 Learning: 2025-09-16T13:33:49.237Z
Learnt from: cardoso
Repo: RocketChat/Rocket.Chat PR: 36890
File: apps/meteor/tests/e2e/e2e-encryption/e2ee-otr.spec.ts:21-26
Timestamp: 2025-09-16T13:33:49.237Z
Learning: The im.delete API endpoint accepts either a `roomId` parameter (requiring the actual DM room _id) or a `username` parameter (for the DM partner's username). Constructing slug-like identifiers like `user2${Users.userE2EE.data.username}` doesn't work for this endpoint.

Applied to files:

  • ee/packages/federation-matrix/src/events/member.ts
📚 Learning: 2025-10-06T20:32:23.658Z
Learnt from: d-gubert
Repo: RocketChat/Rocket.Chat PR: 37152
File: packages/apps-engine/tests/test-data/utilities.ts:557-573
Timestamp: 2025-10-06T20:32:23.658Z
Learning: In packages/apps-engine/tests/test-data/utilities.ts, the field name `isSubscripbedViaBundle` in the `IMarketplaceSubscriptionInfo` type should not be flagged as a typo, as it may match the upstream API's field name.

Applied to files:

  • apps/meteor/lib/publishFields.ts
  • apps/meteor/server/modules/watchers/watchers.module.ts
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: CodeQL-Build
🔇 Additional comments (21)
apps/meteor/lib/publishFields.ts (1)

45-46: LGTM!

The addition of status and inviterUsername fields to the subscription broadcast projection is correct and aligns with the new invite flow support.

packages/models/src/models/Subscriptions.ts (2)

164-164: LGTM!

Filtering out subscriptions with a status field ensures that invited users are not counted as active room members, which is the correct behavior for the invite flow.


2090-2104: LGTM!

The markInviteAsAccepted method correctly transitions an invited subscription to an accepted state by unsetting invite-specific fields and opening the room for the user.

packages/core-typings/src/IInquiry.ts (1)

64-69: LGTM!

The enhanced type guard correctly distinguishes livechat inquiry records from regular subscriptions by validating that the status field contains a LivechatInquiryStatus value, preventing false positives from subscriptions with SubscriptionStatus values.

apps/meteor/server/modules/watchers/watchers.module.ts (1)

140-141: LGTM!

Adding status and inviterUsername to the subscription projection ensures these invite-related fields are properly broadcast to clients when subscriptions change.

packages/core-services/src/types/IRoomService.ts (3)

1-1: LGTM!

Import additions support the extended addUserToRoom options and new acceptRoomInvite method signature.


42-43: LGTM!

The optional status and inviterUsername fields properly extend the options to support the federated invite flow while maintaining backward compatibility.


47-54: LGTM!

The new acceptRoomInvite method signature is well-defined and appropriate for handling the invite acceptance flow with optional system message suppression.

apps/meteor/app/lib/server/functions/addUserToRoom.ts (3)

4-4: LGTM!

Import addition supports the new status parameter for invite handling.


30-31: LGTM!

The optional status and inviterUsername parameters are properly typed and integrated into the function signature.

Also applies to: 36-37


106-107: LGTM!

The conditional spreading ensures status and inviterUsername are only included in the subscription when defined, maintaining data integrity.

apps/meteor/app/lib/server/methods/addUsersToRoom.ts (2)

1-2: LGTM!

Import additions support the new federated room invite integration.


123-133: LGTM!

The early return when newUser.username is undefined prevents issues downstream, and the ephemeral message correctly uses the validated username.

ee/packages/federation-matrix/src/events/member.ts (5)

11-24: LGTM!

The inviter and invitee user resolution with early returns for missing users is a robust approach to error handling.


28-49: LGTM!

The room type determination and naming logic correctly handles direct messages vs. group rooms, with the added check for roomOriginDomain addressing the previous review concern.


72-95: LGTM!

The join handler correctly resolves the joining user, validates the room and subscription exist, and delegates to the room service for invite acceptance.


97-113: LGTM!

The leave handler properly resolves the leaving user and room, with appropriate error logging for missing entities.


115-138: LGTM!

The switch-based dispatcher provides clean routing to the appropriate membership handler with good error handling and logging for unknown membership types.

ee/packages/federation-matrix/src/FederationMatrix.ts (3)

10-20: LGTM!

Type imports properly added to support the new invite handling functionality.


550-589: Verify the subscription status update after invite acceptance/rejection.

The inviteUsersToRoom method now properly distinguishes between native federated and local inviters. However, ensure that when invites are sent, the corresponding subscription records are created or updated with the correct status (e.g., 'INVITED') and that acceptance/rejection flows properly update these records.


916-952: Verify subscription status updates after invite handling.

The handleInvite method correctly validates the subscription is in 'INVITED' status before processing, but ensure that accepting or rejecting the invite properly updates the subscription status (e.g., to 'JOINED' or removes the subscription). This might be handled by Matrix event handlers, but should be confirmed.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
ee/packages/federation-matrix/src/api/_matrix/invite.ts (1)

151-175: Inconsistent error handling: throw vs. structured response.

Lines 154 and 174 throw plain Error objects, while other error paths return structured responses with errcode and statusCode. Thrown errors may not produce proper Matrix-compliant error responses unless caught by an outer handler.

Consider returning structured error responses for consistency:

 		if (!userToCheck) {
-			throw new Error('join event has missing state key, unable to determine user to join');
+			return {
+				body: {
+					errcode: 'M_MISSING_PARAM',
+					error: 'join event has missing state key, unable to determine user to join',
+				},
+				statusCode: 400,
+			};
 		}
 		if (!ourUser) {
-			throw new Error('user not found not processing invite');
+			return {
+				body: {
+					errcode: 'M_NOT_FOUND',
+					error: 'User not found, not processing invite',
+				},
+				statusCode: 404,
+			};
 		}
♻️ Duplicate comments (6)
apps/meteor/server/lib/findUsersOfRoomOrderedByRole.ts (1)

19-21: Type definition doesn't match runtime behavior.

The $unwind stage (lines 114-119) uses preserveNullAndEmptyArrays: true, meaning users without a subscription will have subscription as undefined. However, the type declares it as required. This creates a type safety gap.

Apply this diff to fix the type:

 type UserWithRoleAndSubscriptionData = IUser & {
-	subscription: Pick<ISubscription, '_id' | 'status' | 'ts' | 'roles'>;
+	subscription?: Pick<ISubscription, '_id' | 'status' | 'ts' | 'roles'>;
 };
apps/meteor/app/api/server/v1/rooms.ts (2)

1100-1105: Error handling pattern doesn't leverage response validators.

The endpoint declares 400/401 response validators (lines 1085-1086) but the catch block returns a generic API.v1.failure(). Consider letting errors propagate naturally so the framework handles them with proper response schemas, or differentiate error types to return correctly typed responses.

Consider simplifying by removing the try-catch and letting the framework handle errors:

 async function action() {
   const { roomId, action } = this.bodyParams;
-
-  try {
-    await FederationMatrix.handleInvite(roomId, this.userId, action);
-    return API.v1.success();
-  } catch (error) {
-    return API.v1.failure({ error: `Failed to handle invite: ${error instanceof Error ? error.message : String(error)}` });
-  }
+  await FederationMatrix.handleInvite(roomId, this.userId, action);
+  return API.v1.success();
 },

1097-1102: Parameter mismatch: roomId passed but interface expects subscriptionId.

The endpoint extracts roomId from bodyParams (line 1098) and passes it to FederationMatrix.handleInvite, but the interface signature in IFederationMatrixService.ts defines the first parameter as subscriptionId. Either the parameter name should be subscriptionId in the request body, or the implementation/interface needs alignment.

Verify the intended behavior and align the naming:

#!/bin/bash
# Check the actual implementation of handleInvite to understand expected parameter
ast-grep --pattern 'async handleInvite($_, $_, $_) {
  $$$
}'
apps/meteor/ee/server/hooks/federation/index.ts (1)

105-137: Permission check is still applied to invited user instead of inviter

In this hook, beforeAddUserToRoom runs only for local, user‑initiated actions, so the access-federation check should be enforced on the actor (inviter) rather than the target (user). The current code:

if (!(await Authorization.hasPermission(user._id, 'access-federation'))) {
	throw new MeteorError('error-not-authorized-federation', 'Not authorized to access federation');
}

allows an unauthorized inviter to invite someone who does have access-federation, and blocks inviting a user who lacks the permission even if the inviter is authorized. Based on learnings, this violates the intended pattern for user‑initiated federation actions.

Suggested fix:

if (!(await Authorization.hasPermission(inviter._id, 'access-federation'))) {
	throw new MeteorError('error-not-authorized-federation', 'Not authorized to access federation');
}

(With a preceding guard ensuring inviter._id exists.) This keeps the permission gate on the correct principal.

apps/meteor/app/lib/server/functions/removeUserFromRoom.ts (1)

13-18: JSDoc still claims “no callbacks” but performUserRemoval runs beforeLeaveRoomCallback

The comment on performUserRemoval says it executes “with no callbacks”, yet it invokes beforeLeaveRoomCallback.run(user, room). That’s the same mismatch noted previously.

Either update the JSDoc to mention that beforeLeaveRoomCallback is still executed (and that only app events / afterLeave are skipped on this path), or remove that callback from performUserRemoval if external/event-driven removals truly must avoid all callbacks.

Also applies to: 26-28

ee/packages/federation-matrix/src/events/member.ts (1)

121-172: Guard against missing unsigned and undefined usernames in handleInvite

Two robustness issues here:

  1. const strippedState = unsigned.invite_room_state; will throw if unsigned is undefined. The membership event’s unsigned field is optional, so this path should either use optional chaining or bail out cleanly if invite_room_state is missing.

  2. inviterUser.username and inviteeUser.username are optional on IUser, but they’re used without validation (including a force-cast on inviterUser.username as string). If either is undefined, you’ll build invalid members lists and federation metadata.

Consider:

const strippedState = unsigned?.invite_room_state ?? [];

if (!inviterUser.username || (content?.is_direct && !inviteeUser.username)) {
	logger.error(`Inviter or invitee username missing for invite in room ${roomId}`);
	return;
}

and then use the verified username values without as string casts. This mirrors the username checks already present in other federation paths.

🧹 Nitpick comments (10)
apps/meteor/server/lib/dataExport/exportRoomMessagesToFile.ts (1)

173-175: Consider adding 'ui' and 'uir' to italicTypes for consistent HTML export styling.

System messages like 'uj', 'ul', 'au', 'ru', and 'wm' are rendered in italics for HTML exports. The new invite-related message types ('ui', 'uir') are also system messages and may benefit from the same styling for consistency.

-	const italicTypes: IMessage['t'][] = ['uj', 'ul', 'au', 'r', 'ru', 'wm', 'livechat-close'];
+	const italicTypes: IMessage['t'][] = ['uj', 'ul', 'ui', 'uir', 'au', 'r', 'ru', 'wm', 'livechat-close'];
apps/meteor/server/methods/createDirectMessage.ts (1)

76-88: The extraData pattern looks correct for federation callback mutation.

The refactored approach passes extraData by reference to the federation.beforeCreateDirectMessage callback, allowing the hook to populate federation-related properties without returning values. This avoids the previous issue where callback returns could corrupt room data.

One minor consideration: the empty object {} lacks typing. If you want to be explicit about the expected shape, consider typing it as Partial<IRoom> to match how it's consumed downstream.

-	const extraData = {};
+	const extraData: Partial<IRoom> = {};

This would require importing IRoom from @rocket.chat/core-typings.

ee/packages/federation-matrix/src/api/_matrix/send-leave.ts (2)

13-46: Consider adding required array to nested content object schema.

The content property has a nested membership field that should probably be required for proper validation of a leave event. Currently, the schema only defines the property but doesn't enforce its presence within the content object.

 const isSendLeaveBodyProps = ajv.compile({
 	type: 'object',
 	properties: {
 		content: {
 			type: 'object',
 			properties: {
 				membership: {
 					type: 'string',
 					const: 'leave',
 				},
 			},
+			required: ['membership'],
 		},
 		depth: {

97-97: Inconsistent log message.

The log message says "Error making leave" but this is the send_leave endpoint. Consider updating for clarity.

-			logger.error({ msg: 'Error making leave', err: error });
+			logger.error({ msg: 'Error sending leave', err: error });
ee/packages/federation-matrix/src/api/_matrix/make-leave.ts (1)

13-48: Success response schema missing required array.

The success response schema defines event and room_version properties but doesn't specify which are required. Consider adding a required array to ensure proper validation of the SDK response.

 const isMakeLeaveSuccessResponseProps = ajv.compile({
 	type: 'object',
 	properties: {
 		event: {
 			type: 'object',
 			properties: {
 				content: {
 					type: 'object',
 					properties: {
 						membership: {
 							type: 'string',
 							const: 'leave',
 						},
 					},
 				},
 				origin: {
 					type: 'string',
 				},
 				origin_server_ts: {
 					type: 'number',
 				},
 				sender: {
 					type: 'string',
 				},
 				state_key: {
 					type: 'string',
 				},
 				type: {
 					type: 'string',
 					const: 'm.room.member',
 				},
 			},
 		},
 		room_version: { type: 'string' },
 	},
+	required: ['event', 'room_version'],
 });
apps/meteor/app/lib/server/functions/acceptRoomInvite.ts (1)

18-19: TODO comment indicates technical debt.

The comment acknowledges code duplication with addUserToRoom.ts. Consider creating a shared utility or extracting common logic to reduce maintenance burden in future iterations.

Do you want me to open an issue to track this refactoring task?

apps/meteor/server/lib/findUsersOfRoomOrderedByRole.ts (1)

134-137: Mutating returned objects with delete.

The map callback mutates the member objects by deleting rolePriority. This is a side-effect pattern that can cause issues if the same objects are referenced elsewhere. Consider using destructuring to return new objects without the unwanted property.

 return {
-  members: members.map((member: any) => {
-    delete member.rolePriority;
-    return member;
-  }),
+  members: members.map(({ rolePriority, ...member }) => member as UserWithRoleAndSubscriptionData),
   total: totalCount,
 };
ee/packages/federation-matrix/tests/end-to-end/room.spec.ts (1)

743-744: Hardcoded delays may cause test flakiness.

Multiple setTimeout calls with fixed delays (e.g., 2000ms) are used to wait for federation setup. While acceptable for E2E tests, consider using polling with timeouts or explicit readiness checks if flakiness occurs in CI.

apps/meteor/server/services/room/service.ts (1)

223-289: Centralized subscription creation logic looks correct; verify unread/mention semantics

createUserSubscription correctly consolidates Subscriptions.createWithRoomAndUser, default prefs, autotranslate config, and the various system-message types (ui/au/uj etc.). The INVITED flow via status: 'INVITED' and ui messages matches the invite semantics.

One thing to confirm: unread: 1 and userMentions: 1 are applied unconditionally, including INVITED subscriptions. If the intended UX is “one unread + mention” for invites and joins, this is fine; if not, consider conditioning these counters on status or a flag.

ee/packages/federation-matrix/src/FederationMatrix.ts (1)

91-132: Align createOrUpdateFederatedUser return typing with projection

The function is typed as returning IUser but the findOneAndUpdate uses projection: { _id: 1, username: 1 }, so callers won’t get federated/federation fields even though they’re set in $set. Current call sites only use _id/username, but the wider IUser return type can be misleading.

Consider either:

  • Expanding the projection to include federated and federation, or
  • Narrowing the return type to a Pick<IUser, '_id' | 'username'>-style alias that matches what’s actually returned.
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

Disabled knowledge base sources:

  • Jira integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between 4e0d61a and 78f37b5.

⛔ Files ignored due to path filters (1)
  • yarn.lock is excluded by !**/yarn.lock, !**/*.lock
📒 Files selected for processing (41)
  • apps/meteor/app/api/server/v1/rooms.ts (3 hunks)
  • apps/meteor/app/lib/lib/MessageTypes.ts (1 hunks)
  • apps/meteor/app/lib/server/functions/acceptRoomInvite.ts (1 hunks)
  • apps/meteor/app/lib/server/functions/addUserToRoom.ts (4 hunks)
  • apps/meteor/app/lib/server/functions/createDirectRoom.ts (2 hunks)
  • apps/meteor/app/lib/server/functions/createRoom.ts (6 hunks)
  • apps/meteor/app/lib/server/functions/removeUserFromRoom.ts (4 hunks)
  • apps/meteor/app/lib/server/methods/addUsersToRoom.ts (1 hunks)
  • apps/meteor/ee/server/hooks/federation/index.ts (4 hunks)
  • apps/meteor/lib/callbacks.ts (1 hunks)
  • apps/meteor/lib/callbacks/beforeCreateRoomCallback.ts (1 hunks)
  • apps/meteor/lib/publishFields.ts (1 hunks)
  • apps/meteor/package.json (1 hunks)
  • apps/meteor/server/lib/dataExport/exportRoomMessagesToFile.ts (1 hunks)
  • apps/meteor/server/lib/findUsersOfRoomOrderedByRole.ts (6 hunks)
  • apps/meteor/server/methods/createDirectMessage.ts (1 hunks)
  • apps/meteor/server/modules/watchers/watchers.module.ts (1 hunks)
  • apps/meteor/server/services/room/service.ts (3 hunks)
  • apps/meteor/tests/data/rooms.helper.ts (1 hunks)
  • ee/packages/federation-matrix/package.json (1 hunks)
  • ee/packages/federation-matrix/src/FederationMatrix.ts (9 hunks)
  • ee/packages/federation-matrix/src/api/_matrix/invite.ts (3 hunks)
  • ee/packages/federation-matrix/src/api/_matrix/make-leave.ts (1 hunks)
  • ee/packages/federation-matrix/src/api/_matrix/send-leave.ts (1 hunks)
  • ee/packages/federation-matrix/src/api/routes.ts (2 hunks)
  • ee/packages/federation-matrix/src/events/member.ts (1 hunks)
  • ee/packages/federation-matrix/tests/end-to-end/room.spec.ts (13 hunks)
  • packages/apps-engine/src/definition/messages/MessageType.ts (1 hunks)
  • packages/core-services/package.json (1 hunks)
  • packages/core-services/src/types/IFederationMatrixService.ts (2 hunks)
  • packages/core-services/src/types/IRoomService.ts (4 hunks)
  • packages/core-typings/src/IMessage/IMessage.ts (1 hunks)
  • packages/core-typings/src/IRoom.ts (1 hunks)
  • packages/core-typings/src/ISubscription.ts (2 hunks)
  • packages/i18n/src/locales/en.i18n.json (2 hunks)
  • packages/message-types/src/registrations/common.ts (1 hunks)
  • packages/model-typings/src/models/IRoomsModel.ts (1 hunks)
  • packages/model-typings/src/models/ISubscriptionsModel.ts (1 hunks)
  • packages/models/src/models/Rooms.ts (1 hunks)
  • packages/models/src/models/Subscriptions.ts (2 hunks)
  • packages/rest-typings/src/v1/rooms.ts (3 hunks)
🚧 Files skipped from review as they are similar to previous changes (17)
  • packages/core-services/package.json
  • apps/meteor/lib/callbacks.ts
  • apps/meteor/app/lib/lib/MessageTypes.ts
  • packages/models/src/models/Rooms.ts
  • apps/meteor/app/lib/server/functions/createDirectRoom.ts
  • packages/message-types/src/registrations/common.ts
  • packages/model-typings/src/models/IRoomsModel.ts
  • packages/i18n/src/locales/en.i18n.json
  • apps/meteor/lib/publishFields.ts
  • packages/apps-engine/src/definition/messages/MessageType.ts
  • packages/core-typings/src/IMessage/IMessage.ts
  • apps/meteor/package.json
  • apps/meteor/tests/data/rooms.helper.ts
  • packages/core-typings/src/ISubscription.ts
  • apps/meteor/app/lib/server/methods/addUsersToRoom.ts
  • apps/meteor/lib/callbacks/beforeCreateRoomCallback.ts
  • ee/packages/federation-matrix/package.json
🧰 Additional context used
📓 Path-based instructions (2)
**/*.{ts,tsx,js}

📄 CodeRabbit inference engine (.cursor/rules/playwright.mdc)

**/*.{ts,tsx,js}: Write concise, technical TypeScript/JavaScript with accurate typing in Playwright tests
Avoid code comments in the implementation

Files:

  • packages/core-typings/src/IRoom.ts
  • packages/model-typings/src/models/ISubscriptionsModel.ts
  • ee/packages/federation-matrix/src/api/routes.ts
  • ee/packages/federation-matrix/src/api/_matrix/invite.ts
  • packages/models/src/models/Subscriptions.ts
  • apps/meteor/server/modules/watchers/watchers.module.ts
  • ee/packages/federation-matrix/src/api/_matrix/send-leave.ts
  • apps/meteor/server/lib/dataExport/exportRoomMessagesToFile.ts
  • apps/meteor/app/api/server/v1/rooms.ts
  • apps/meteor/server/methods/createDirectMessage.ts
  • packages/core-services/src/types/IFederationMatrixService.ts
  • apps/meteor/app/lib/server/functions/acceptRoomInvite.ts
  • ee/packages/federation-matrix/src/api/_matrix/make-leave.ts
  • ee/packages/federation-matrix/tests/end-to-end/room.spec.ts
  • ee/packages/federation-matrix/src/events/member.ts
  • apps/meteor/app/lib/server/functions/addUserToRoom.ts
  • apps/meteor/app/lib/server/functions/removeUserFromRoom.ts
  • packages/rest-typings/src/v1/rooms.ts
  • packages/core-services/src/types/IRoomService.ts
  • apps/meteor/app/lib/server/functions/createRoom.ts
  • apps/meteor/server/lib/findUsersOfRoomOrderedByRole.ts
  • ee/packages/federation-matrix/src/FederationMatrix.ts
  • apps/meteor/server/services/room/service.ts
  • apps/meteor/ee/server/hooks/federation/index.ts
**/*.spec.ts

📄 CodeRabbit inference engine (.cursor/rules/playwright.mdc)

**/*.spec.ts: Use descriptive test names that clearly communicate expected behavior in Playwright tests
Use .spec.ts extension for test files (e.g., login.spec.ts)

Files:

  • ee/packages/federation-matrix/tests/end-to-end/room.spec.ts
🧠 Learnings (26)
📓 Common learnings
Learnt from: sampaiodiego
Repo: RocketChat/Rocket.Chat PR: 37532
File: ee/packages/federation-matrix/src/FederationMatrix.ts:920-927
Timestamp: 2025-12-09T20:01:00.324Z
Learning: In Rocket.Chat's federation invite handling (ee/packages/federation-matrix/src/FederationMatrix.ts), when a user rejects an invite via federationSDK.rejectInvite(), the subscription cleanup happens automatically through an event-driven flow: Matrix emits a leave event back, which is processed by handleLeave() in ee/packages/federation-matrix/src/events/member.ts, and that function calls Room.performUserRemoval() to clean up the subscription. No explicit cleanup is needed in the reject branch of handleInvite() because the leave event handler takes care of it.
<!-- </add_learning>
Learnt from: ricardogarim
Repo: RocketChat/Rocket.Chat PR: 37377
File: apps/meteor/ee/server/hooks/federation/index.ts:86-88
Timestamp: 2025-11-04T16:49:19.107Z
Learning: In Rocket.Chat's federation system (apps/meteor/ee/server/hooks/federation/), permission checks follow two distinct patterns: (1) User-initiated federation actions (creating rooms, adding users to federated rooms, joining from invites) should throw MeteorError to inform users they lack 'access-federation' permission. (2) Remote server-initiated federation events should silently skip/ignore when users lack permission. The beforeAddUserToRoom hook only executes for local user-initiated actions, so throwing an error there is correct. Remote federation events are handled separately by the federation Matrix package with silent skipping logic.
Learnt from: ricardogarim
Repo: RocketChat/Rocket.Chat PR: 37205
File: ee/packages/federation-matrix/src/FederationMatrix.ts:296-301
Timestamp: 2025-10-28T16:53:42.761Z
Learning: In the Rocket.Chat federation-matrix integration (ee/packages/federation-matrix/), the createRoom method from rocket.chat/federation-sdk will support a 4-argument signature (userId, roomName, visibility, displayName) in newer versions. Code using this 4-argument call is forward-compatible with planned library updates and should not be flagged as an error.
Learnt from: ricardogarim
Repo: RocketChat/Rocket.Chat PR: 37205
File: ee/packages/federation-matrix/src/FederationMatrix.ts:296-301
Timestamp: 2025-10-28T16:53:42.761Z
Learning: In the Rocket.Chat federation-matrix integration (ee/packages/federation-matrix/), the createRoom method from rocket.chat/federation-sdk will support a 4-argument signature (userId, roomName, visibility, displayName) in newer versions. Code using this 4-argument call is forward-compatible with planned library updates and should not be flagged as an error.
📚 Learning: 2025-10-28T16:53:42.761Z
Learnt from: ricardogarim
Repo: RocketChat/Rocket.Chat PR: 37205
File: ee/packages/federation-matrix/src/FederationMatrix.ts:296-301
Timestamp: 2025-10-28T16:53:42.761Z
Learning: In the Rocket.Chat federation-matrix integration (ee/packages/federation-matrix/), the createRoom method from rocket.chat/federation-sdk will support a 4-argument signature (userId, roomName, visibility, displayName) in newer versions. Code using this 4-argument call is forward-compatible with planned library updates and should not be flagged as an error.

Applied to files:

  • packages/core-typings/src/IRoom.ts
  • ee/packages/federation-matrix/src/api/_matrix/invite.ts
  • ee/packages/federation-matrix/src/api/_matrix/send-leave.ts
  • apps/meteor/server/lib/dataExport/exportRoomMessagesToFile.ts
  • apps/meteor/app/api/server/v1/rooms.ts
  • apps/meteor/server/methods/createDirectMessage.ts
  • packages/core-services/src/types/IFederationMatrixService.ts
  • apps/meteor/app/lib/server/functions/acceptRoomInvite.ts
  • ee/packages/federation-matrix/src/api/_matrix/make-leave.ts
  • ee/packages/federation-matrix/tests/end-to-end/room.spec.ts
  • ee/packages/federation-matrix/src/events/member.ts
  • apps/meteor/app/lib/server/functions/addUserToRoom.ts
  • apps/meteor/app/lib/server/functions/removeUserFromRoom.ts
  • packages/rest-typings/src/v1/rooms.ts
  • packages/core-services/src/types/IRoomService.ts
  • apps/meteor/app/lib/server/functions/createRoom.ts
  • apps/meteor/server/lib/findUsersOfRoomOrderedByRole.ts
  • ee/packages/federation-matrix/src/FederationMatrix.ts
  • apps/meteor/server/services/room/service.ts
  • apps/meteor/ee/server/hooks/federation/index.ts
📚 Learning: 2025-09-19T15:15:04.642Z
Learnt from: rodrigok
Repo: RocketChat/Rocket.Chat PR: 36991
File: apps/meteor/server/services/federation/infrastructure/rocket-chat/adapters/Settings.ts:219-221
Timestamp: 2025-09-19T15:15:04.642Z
Learning: The Federation_Matrix_homeserver_domain setting in apps/meteor/server/services/federation/infrastructure/rocket-chat/adapters/Settings.ts is part of the old federation system and is being deprecated/removed, so configuration issues with this setting should not be flagged for improvement.

Applied to files:

  • packages/core-typings/src/IRoom.ts
  • ee/packages/federation-matrix/src/api/_matrix/invite.ts
  • apps/meteor/app/api/server/v1/rooms.ts
  • apps/meteor/server/methods/createDirectMessage.ts
  • packages/core-services/src/types/IFederationMatrixService.ts
  • ee/packages/federation-matrix/src/events/member.ts
  • apps/meteor/app/lib/server/functions/addUserToRoom.ts
  • apps/meteor/app/lib/server/functions/removeUserFromRoom.ts
  • apps/meteor/app/lib/server/functions/createRoom.ts
  • ee/packages/federation-matrix/src/FederationMatrix.ts
  • apps/meteor/ee/server/hooks/federation/index.ts
📚 Learning: 2025-11-04T16:49:19.107Z
Learnt from: ricardogarim
Repo: RocketChat/Rocket.Chat PR: 37377
File: apps/meteor/ee/server/hooks/federation/index.ts:86-88
Timestamp: 2025-11-04T16:49:19.107Z
Learning: In Rocket.Chat's federation system (apps/meteor/ee/server/hooks/federation/), permission checks follow two distinct patterns: (1) User-initiated federation actions (creating rooms, adding users to federated rooms, joining from invites) should throw MeteorError to inform users they lack 'access-federation' permission. (2) Remote server-initiated federation events should silently skip/ignore when users lack permission. The beforeAddUserToRoom hook only executes for local user-initiated actions, so throwing an error there is correct. Remote federation events are handled separately by the federation Matrix package with silent skipping logic.

Applied to files:

  • packages/core-typings/src/IRoom.ts
  • ee/packages/federation-matrix/src/api/_matrix/invite.ts
  • ee/packages/federation-matrix/src/api/_matrix/send-leave.ts
  • apps/meteor/app/api/server/v1/rooms.ts
  • apps/meteor/server/methods/createDirectMessage.ts
  • packages/core-services/src/types/IFederationMatrixService.ts
  • apps/meteor/app/lib/server/functions/acceptRoomInvite.ts
  • ee/packages/federation-matrix/src/api/_matrix/make-leave.ts
  • ee/packages/federation-matrix/tests/end-to-end/room.spec.ts
  • ee/packages/federation-matrix/src/events/member.ts
  • apps/meteor/app/lib/server/functions/addUserToRoom.ts
  • apps/meteor/app/lib/server/functions/removeUserFromRoom.ts
  • packages/rest-typings/src/v1/rooms.ts
  • apps/meteor/app/lib/server/functions/createRoom.ts
  • apps/meteor/server/lib/findUsersOfRoomOrderedByRole.ts
  • ee/packages/federation-matrix/src/FederationMatrix.ts
  • apps/meteor/server/services/room/service.ts
  • apps/meteor/ee/server/hooks/federation/index.ts
📚 Learning: 2025-10-06T20:32:23.658Z
Learnt from: d-gubert
Repo: RocketChat/Rocket.Chat PR: 37152
File: packages/apps-engine/tests/test-data/utilities.ts:557-573
Timestamp: 2025-10-06T20:32:23.658Z
Learning: In packages/apps-engine/tests/test-data/utilities.ts, the field name `isSubscripbedViaBundle` in the `IMarketplaceSubscriptionInfo` type should not be flagged as a typo, as it may match the upstream API's field name.

Applied to files:

  • packages/model-typings/src/models/ISubscriptionsModel.ts
  • apps/meteor/server/modules/watchers/watchers.module.ts
  • apps/meteor/server/lib/findUsersOfRoomOrderedByRole.ts
  • apps/meteor/server/services/room/service.ts
📚 Learning: 2025-09-25T09:59:26.461Z
Learnt from: Dnouv
Repo: RocketChat/Rocket.Chat PR: 37057
File: packages/apps-engine/src/definition/accessors/IUserRead.ts:23-27
Timestamp: 2025-09-25T09:59:26.461Z
Learning: AppUserBridge.getUserRoomIds in apps/meteor/app/apps/server/bridges/users.ts always returns an array of strings by mapping subscription documents to room IDs, never undefined, even when user has no room subscriptions.

Applied to files:

  • packages/model-typings/src/models/ISubscriptionsModel.ts
  • packages/models/src/models/Subscriptions.ts
  • apps/meteor/server/methods/createDirectMessage.ts
  • packages/core-services/src/types/IFederationMatrixService.ts
  • apps/meteor/app/lib/server/functions/acceptRoomInvite.ts
  • ee/packages/federation-matrix/src/events/member.ts
  • apps/meteor/app/lib/server/functions/addUserToRoom.ts
  • apps/meteor/app/lib/server/functions/removeUserFromRoom.ts
  • packages/rest-typings/src/v1/rooms.ts
  • packages/core-services/src/types/IRoomService.ts
  • apps/meteor/app/lib/server/functions/createRoom.ts
  • apps/meteor/server/lib/findUsersOfRoomOrderedByRole.ts
  • ee/packages/federation-matrix/src/FederationMatrix.ts
  • apps/meteor/server/services/room/service.ts
  • apps/meteor/ee/server/hooks/federation/index.ts
📚 Learning: 2025-09-25T09:59:26.461Z
Learnt from: Dnouv
Repo: RocketChat/Rocket.Chat PR: 37057
File: packages/apps-engine/src/definition/accessors/IUserRead.ts:23-27
Timestamp: 2025-09-25T09:59:26.461Z
Learning: AppUserBridge.getUserRoomIds in apps/meteor/app/apps/server/bridges/users.ts always returns an array of strings (mapping subscription documents to room IDs), never undefined, even when user has no room subscriptions.

Applied to files:

  • packages/model-typings/src/models/ISubscriptionsModel.ts
  • packages/models/src/models/Subscriptions.ts
  • apps/meteor/server/methods/createDirectMessage.ts
  • packages/core-services/src/types/IFederationMatrixService.ts
  • apps/meteor/app/lib/server/functions/acceptRoomInvite.ts
  • ee/packages/federation-matrix/src/events/member.ts
  • apps/meteor/app/lib/server/functions/addUserToRoom.ts
  • apps/meteor/app/lib/server/functions/removeUserFromRoom.ts
  • packages/rest-typings/src/v1/rooms.ts
  • packages/core-services/src/types/IRoomService.ts
  • apps/meteor/app/lib/server/functions/createRoom.ts
  • apps/meteor/server/lib/findUsersOfRoomOrderedByRole.ts
  • ee/packages/federation-matrix/src/FederationMatrix.ts
  • apps/meteor/server/services/room/service.ts
  • apps/meteor/ee/server/hooks/federation/index.ts
📚 Learning: 2025-12-09T20:01:00.324Z
Learnt from: sampaiodiego
Repo: RocketChat/Rocket.Chat PR: 37532
File: ee/packages/federation-matrix/src/FederationMatrix.ts:920-927
Timestamp: 2025-12-09T20:01:00.324Z
Learning: In Rocket.Chat's federation invite handling (ee/packages/federation-matrix/src/FederationMatrix.ts), when a user rejects an invite via federationSDK.rejectInvite(), the subscription cleanup happens automatically through an event-driven flow: Matrix emits a leave event back, which is processed by handleLeave() in ee/packages/federation-matrix/src/events/member.ts, and that function calls Room.performUserRemoval() to clean up the subscription. No explicit cleanup is needed in the reject branch of handleInvite() because the leave event handler takes care of it.
<!-- </add_learning>

Applied to files:

  • packages/model-typings/src/models/ISubscriptionsModel.ts
  • packages/models/src/models/Subscriptions.ts
  • apps/meteor/app/api/server/v1/rooms.ts
  • apps/meteor/server/methods/createDirectMessage.ts
  • packages/core-services/src/types/IFederationMatrixService.ts
  • apps/meteor/app/lib/server/functions/acceptRoomInvite.ts
  • apps/meteor/app/lib/server/functions/addUserToRoom.ts
  • apps/meteor/app/lib/server/functions/removeUserFromRoom.ts
  • packages/rest-typings/src/v1/rooms.ts
  • packages/core-services/src/types/IRoomService.ts
  • apps/meteor/app/lib/server/functions/createRoom.ts
  • apps/meteor/server/services/room/service.ts
  • apps/meteor/ee/server/hooks/federation/index.ts
📚 Learning: 2025-12-09T20:01:00.324Z
Learnt from: sampaiodiego
Repo: RocketChat/Rocket.Chat PR: 37532
File: ee/packages/federation-matrix/src/FederationMatrix.ts:920-927
Timestamp: 2025-12-09T20:01:00.324Z
Learning: When reviewing federation invite handling in Rocket.Chat (specifically under ee/packages/federation-matrix), understand that rejecting an invite via federationSDK.rejectInvite() triggers an event-driven cleanup: a leave event is emitted and handled by handleLeave() in ee/packages/federation-matrix/src/events/member.ts, which calls Room.performUserRemoval() to remove the subscription. Do not add explicit cleanup in the reject branch of handleInvite(); rely on the existing leave-event flow for cleanup. If making changes, ensure this invariant remains and that any related paths still funnel cleanup through the leave event to avoid duplicate or missing removals.

Applied to files:

  • ee/packages/federation-matrix/src/api/routes.ts
  • ee/packages/federation-matrix/src/api/_matrix/invite.ts
  • ee/packages/federation-matrix/src/api/_matrix/send-leave.ts
  • ee/packages/federation-matrix/src/api/_matrix/make-leave.ts
  • ee/packages/federation-matrix/tests/end-to-end/room.spec.ts
  • ee/packages/federation-matrix/src/events/member.ts
  • ee/packages/federation-matrix/src/FederationMatrix.ts
📚 Learning: 2025-11-05T21:04:35.787Z
Learnt from: sampaiodiego
Repo: RocketChat/Rocket.Chat PR: 37357
File: ee/packages/federation-matrix/src/setup.ts:103-120
Timestamp: 2025-11-05T21:04:35.787Z
Learning: In Rocket.Chat's federation-matrix setup (ee/packages/federation-matrix/src/setup.ts and apps/meteor/ee/server/startup/federation.ts), configureFederationMatrixSettings does not need to be called before setupFederationMatrix. The SDK's init() establishes infrastructure (database, event handlers, APIs) first, and the configuration can be applied later via settings watchers before actual federation events are processed. The config only matters when events actually occur, at which point all infrastructure is already configured.

Applied to files:

  • ee/packages/federation-matrix/src/api/routes.ts
  • ee/packages/federation-matrix/src/api/_matrix/invite.ts
  • apps/meteor/app/api/server/v1/rooms.ts
  • apps/meteor/server/methods/createDirectMessage.ts
  • packages/core-services/src/types/IFederationMatrixService.ts
  • ee/packages/federation-matrix/src/events/member.ts
  • apps/meteor/app/lib/server/functions/createRoom.ts
  • ee/packages/federation-matrix/src/FederationMatrix.ts
  • apps/meteor/ee/server/hooks/federation/index.ts
📚 Learning: 2025-11-19T18:20:07.720Z
Learnt from: gabriellsh
Repo: RocketChat/Rocket.Chat PR: 37419
File: packages/i18n/src/locales/en.i18n.json:918-921
Timestamp: 2025-11-19T18:20:07.720Z
Learning: Repo: RocketChat/Rocket.Chat — i18n/formatting
Learning: This repository uses a custom message formatting parser in UI blocks/messages; do not assume standard Markdown rules. For keys like Call_ended_bold, Call_not_answered_bold, Call_failed_bold, and Call_transferred_bold in packages/i18n/src/locales/en.i18n.json, retain the existing single-asterisk emphasis unless maintainers request otherwise.

Applied to files:

  • apps/meteor/server/lib/dataExport/exportRoomMessagesToFile.ts
  • ee/packages/federation-matrix/src/FederationMatrix.ts
📚 Learning: 2025-11-27T17:56:26.050Z
Learnt from: MartinSchoeler
Repo: RocketChat/Rocket.Chat PR: 37557
File: apps/meteor/client/views/admin/ABAC/AdminABACRooms.tsx:115-116
Timestamp: 2025-11-27T17:56:26.050Z
Learning: In Rocket.Chat, the GET /v1/abac/rooms endpoint (implemented in ee/packages/abac/src/index.ts) only returns rooms where abacAttributes exists and is not an empty array (query: { abacAttributes: { $exists: true, $ne: [] } }). Therefore, in components consuming this endpoint (like AdminABACRooms.tsx), room.abacAttributes is guaranteed to be defined for all returned rooms, and optional chaining before calling array methods like .join() is sufficient without additional null coalescing.

Applied to files:

  • apps/meteor/app/api/server/v1/rooms.ts
  • apps/meteor/server/methods/createDirectMessage.ts
  • ee/packages/federation-matrix/src/events/member.ts
  • packages/rest-typings/src/v1/rooms.ts
  • ee/packages/federation-matrix/src/FederationMatrix.ts
  • apps/meteor/server/services/room/service.ts
  • apps/meteor/ee/server/hooks/federation/index.ts
📚 Learning: 2025-09-25T09:59:26.461Z
Learnt from: Dnouv
Repo: RocketChat/Rocket.Chat PR: 37057
File: packages/apps-engine/src/definition/accessors/IUserRead.ts:23-27
Timestamp: 2025-09-25T09:59:26.461Z
Learning: UserBridge.doGetUserRoomIds in packages/apps-engine/src/server/bridges/UserBridge.ts has a bug where it implicitly returns undefined when the app lacks read permission (missing return statement in the else case of the permission check).

Applied to files:

  • apps/meteor/app/api/server/v1/rooms.ts
  • apps/meteor/server/methods/createDirectMessage.ts
  • packages/core-services/src/types/IFederationMatrixService.ts
  • apps/meteor/app/lib/server/functions/acceptRoomInvite.ts
  • ee/packages/federation-matrix/src/events/member.ts
  • apps/meteor/app/lib/server/functions/addUserToRoom.ts
  • apps/meteor/app/lib/server/functions/removeUserFromRoom.ts
  • packages/rest-typings/src/v1/rooms.ts
  • apps/meteor/server/lib/findUsersOfRoomOrderedByRole.ts
  • apps/meteor/server/services/room/service.ts
  • apps/meteor/ee/server/hooks/federation/index.ts
📚 Learning: 2025-11-19T18:20:37.116Z
Learnt from: gabriellsh
Repo: RocketChat/Rocket.Chat PR: 37419
File: apps/meteor/server/services/media-call/service.ts:141-141
Timestamp: 2025-11-19T18:20:37.116Z
Learning: In apps/meteor/server/services/media-call/service.ts, the sendHistoryMessage method should use call.caller.id or call.createdBy?.id as the message author, not call.transferredBy?.id. Even for transferred calls, the message should appear in the DM between the two users who are calling each other, not sent by the person who transferred the call.

Applied to files:

  • apps/meteor/server/methods/createDirectMessage.ts
  • ee/packages/federation-matrix/src/events/member.ts
  • apps/meteor/ee/server/hooks/federation/index.ts
📚 Learning: 2025-09-16T13:33:49.237Z
Learnt from: cardoso
Repo: RocketChat/Rocket.Chat PR: 36890
File: apps/meteor/tests/e2e/e2e-encryption/e2ee-otr.spec.ts:21-26
Timestamp: 2025-09-16T13:33:49.237Z
Learning: The im.delete API endpoint accepts either a `roomId` parameter (requiring the actual DM room _id) or a `username` parameter (for the DM partner's username). Constructing slug-like identifiers like `user2${Users.userE2EE.data.username}` doesn't work for this endpoint.

Applied to files:

  • apps/meteor/server/methods/createDirectMessage.ts
  • ee/packages/federation-matrix/src/events/member.ts
  • apps/meteor/app/lib/server/functions/removeUserFromRoom.ts
📚 Learning: 2025-09-16T13:33:49.237Z
Learnt from: cardoso
Repo: RocketChat/Rocket.Chat PR: 36890
File: apps/meteor/tests/e2e/e2e-encryption/e2ee-otr.spec.ts:21-26
Timestamp: 2025-09-16T13:33:49.237Z
Learning: In Rocket.Chat test files, the im.delete API endpoint accepts either a `roomId` parameter (requiring the actual DM room _id) or a `username` parameter (for the DM partner's username). It does not accept slug-like constructions such as concatenating usernames together.

Applied to files:

  • apps/meteor/server/methods/createDirectMessage.ts
📚 Learning: 2025-11-24T17:08:17.065Z
Learnt from: CR
Repo: RocketChat/Rocket.Chat PR: 0
File: .cursor/rules/playwright.mdc:0-0
Timestamp: 2025-11-24T17:08:17.065Z
Learning: Applies to apps/meteor/tests/e2e/**/*.spec.ts : Utilize Playwright fixtures (`test`, `page`, `expect`) for consistency in test files

Applied to files:

  • ee/packages/federation-matrix/tests/end-to-end/room.spec.ts
📚 Learning: 2025-11-24T17:08:17.065Z
Learnt from: CR
Repo: RocketChat/Rocket.Chat PR: 0
File: .cursor/rules/playwright.mdc:0-0
Timestamp: 2025-11-24T17:08:17.065Z
Learning: Applies to apps/meteor/tests/e2e/**/*.spec.ts : Ensure tests run reliably in parallel without shared state conflicts

Applied to files:

  • ee/packages/federation-matrix/tests/end-to-end/room.spec.ts
📚 Learning: 2025-11-24T17:08:17.065Z
Learnt from: CR
Repo: RocketChat/Rocket.Chat PR: 0
File: .cursor/rules/playwright.mdc:0-0
Timestamp: 2025-11-24T17:08:17.065Z
Learning: Applies to apps/meteor/tests/e2e/**/*.spec.ts : Use `expect` matchers for assertions (`toEqual`, `toContain`, `toBeTruthy`, `toHaveLength`, etc.) instead of `assert` statements in Playwright tests

Applied to files:

  • ee/packages/federation-matrix/tests/end-to-end/room.spec.ts
📚 Learning: 2025-11-24T17:08:17.065Z
Learnt from: CR
Repo: RocketChat/Rocket.Chat PR: 0
File: .cursor/rules/playwright.mdc:0-0
Timestamp: 2025-11-24T17:08:17.065Z
Learning: Applies to apps/meteor/tests/e2e/**/*.spec.ts : Use `test.step()` for complex test scenarios to improve organization in Playwright tests

Applied to files:

  • ee/packages/federation-matrix/tests/end-to-end/room.spec.ts
📚 Learning: 2025-11-24T17:08:17.065Z
Learnt from: CR
Repo: RocketChat/Rocket.Chat PR: 0
File: .cursor/rules/playwright.mdc:0-0
Timestamp: 2025-11-24T17:08:17.065Z
Learning: Applies to apps/meteor/tests/e2e/**/*.spec.ts : Group related tests in the same file

Applied to files:

  • ee/packages/federation-matrix/tests/end-to-end/room.spec.ts
📚 Learning: 2025-11-24T17:08:17.065Z
Learnt from: CR
Repo: RocketChat/Rocket.Chat PR: 0
File: .cursor/rules/playwright.mdc:0-0
Timestamp: 2025-11-24T17:08:17.065Z
Learning: Applies to apps/meteor/tests/e2e/page-objects/**/*.ts : Utilize existing page objects pattern from `apps/meteor/tests/e2e/page-objects/`

Applied to files:

  • ee/packages/federation-matrix/tests/end-to-end/room.spec.ts
📚 Learning: 2025-11-24T17:08:17.065Z
Learnt from: CR
Repo: RocketChat/Rocket.Chat PR: 0
File: .cursor/rules/playwright.mdc:0-0
Timestamp: 2025-11-24T17:08:17.065Z
Learning: Applies to apps/meteor/tests/e2e/**/*.{ts,spec.ts} : Store commonly used locators in variables/constants for reuse

Applied to files:

  • ee/packages/federation-matrix/tests/end-to-end/room.spec.ts
📚 Learning: 2025-11-10T19:06:20.146Z
Learnt from: MartinSchoeler
Repo: RocketChat/Rocket.Chat PR: 37408
File: apps/meteor/client/views/admin/ABAC/useRoomAttributeOptions.tsx:53-69
Timestamp: 2025-11-10T19:06:20.146Z
Learning: In the Rocket.Chat repository, do not provide suggestions or recommendations about code sections marked with TODO comments. The maintainers have already identified these as future work and external reviewers lack the full context about implementation plans and timing.

Applied to files:

  • ee/packages/federation-matrix/src/events/member.ts
  • ee/packages/federation-matrix/src/FederationMatrix.ts
📚 Learning: 2025-09-30T13:00:05.465Z
Learnt from: d-gubert
Repo: RocketChat/Rocket.Chat PR: 36990
File: apps/meteor/ee/server/apps/storage/AppRealStorage.ts:55-58
Timestamp: 2025-09-30T13:00:05.465Z
Learning: In AppRealStorage (apps/meteor/ee/server/apps/storage/AppRealStorage.ts), the `remove` method is designed to be idempotent and returns `{ success: true }` unconditionally because the goal is to ensure the app is removed, not to distinguish whether this specific call performed the deletion. Database errors will throw exceptions.

Applied to files:

  • apps/meteor/app/lib/server/functions/removeUserFromRoom.ts
📚 Learning: 2025-11-19T12:32:29.696Z
Learnt from: d-gubert
Repo: RocketChat/Rocket.Chat PR: 37547
File: packages/i18n/src/locales/en.i18n.json:634-634
Timestamp: 2025-11-19T12:32:29.696Z
Learning: Repo: RocketChat/Rocket.Chat
Context: i18n workflow
Learning: In this repository, new translation keys should be added to packages/i18n/src/locales/en.i18n.json only; other locale files are populated via the external translation pipeline and/or fall back to English. Do not request adding the same key to all locale files in future reviews.

Applied to files:

  • ee/packages/federation-matrix/src/FederationMatrix.ts
🧬 Code graph analysis (17)
packages/model-typings/src/models/ISubscriptionsModel.ts (1)
packages/core-typings/src/ISubscription.ts (1)
  • ISubscription (11-79)
ee/packages/federation-matrix/src/api/routes.ts (2)
ee/packages/federation-matrix/src/api/_matrix/send-leave.ts (1)
  • getMatrixSendLeaveRoutes (60-109)
ee/packages/federation-matrix/src/api/_matrix/make-leave.ts (1)
  • getMatrixMakeLeaveRoutes (58-106)
packages/models/src/models/Subscriptions.ts (1)
packages/core-typings/src/ISubscription.ts (1)
  • ISubscription (11-79)
ee/packages/federation-matrix/src/api/_matrix/send-leave.ts (2)
packages/rest-typings/src/v1/Ajv.ts (1)
  • ajv (24-24)
ee/packages/federation-matrix/src/api/middlewares/isAuthenticated.ts (1)
  • isAuthenticatedMiddleware (5-39)
apps/meteor/app/api/server/v1/rooms.ts (5)
apps/meteor/app/api/server/index.ts (1)
  • API (55-55)
packages/rest-typings/src/v1/rooms.ts (1)
  • isRoomsInviteProps (712-712)
packages/rest-typings/src/v1/Ajv.ts (3)
  • validateBadRequestErrorResponse (47-47)
  • validateUnauthorizedErrorResponse (70-70)
  • ajv (24-24)
ee/packages/federation-matrix/src/FederationMatrix.ts (1)
  • FederationMatrix (136-929)
apps/meteor/app/api/server/ApiClass.ts (1)
  • ExtractRoutesFromAPI (73-77)
apps/meteor/server/methods/createDirectMessage.ts (2)
apps/meteor/app/lib/server/functions/createRoom.ts (1)
  • createRoom (144-325)
packages/core-typings/src/IUser.ts (1)
  • IUser (186-256)
packages/core-services/src/types/IFederationMatrixService.ts (3)
packages/core-typings/src/IRoom.ts (1)
  • IRoomFederated (109-112)
packages/core-typings/src/IUser.ts (1)
  • IUser (186-256)
packages/core-typings/src/ISubscription.ts (1)
  • ISubscription (11-79)
apps/meteor/app/lib/server/functions/acceptRoomInvite.ts (6)
apps/meteor/server/services/room/service.ts (1)
  • performAcceptRoomInvite (93-95)
packages/core-typings/src/IRoom.ts (1)
  • IRoom (21-95)
packages/core-typings/src/ISubscription.ts (1)
  • ISubscription (11-79)
packages/core-typings/src/IUser.ts (1)
  • IUser (186-256)
apps/meteor/lib/callbacks.ts (1)
  • callbacks (252-260)
apps/meteor/app/lib/server/lib/notifyListener.ts (1)
  • notifyOnSubscriptionChangedById (535-544)
ee/packages/federation-matrix/tests/end-to-end/room.spec.ts (2)
apps/meteor/tests/data/rooms.helper.ts (3)
  • getGroupHistory (343-358)
  • acceptRoomInvite (439-455)
  • rejectRoomInvite (468-484)
packages/core-typings/src/IMessage/IMessage.ts (1)
  • IMessage (164-262)
ee/packages/federation-matrix/src/events/member.ts (1)
ee/packages/federation-matrix/src/FederationMatrix.ts (2)
  • getUsernameServername (72-84)
  • createOrUpdateFederatedUser (91-132)
apps/meteor/app/lib/server/functions/addUserToRoom.ts (2)
packages/core-typings/src/IRoom.ts (1)
  • isRoomNativeFederated (125-126)
packages/core-services/src/index.ts (1)
  • Room (169-169)
packages/rest-typings/src/v1/rooms.ts (2)
packages/core-typings/src/IUser.ts (1)
  • IUser (186-256)
packages/core-typings/src/ISubscription.ts (1)
  • ISubscription (11-79)
packages/core-services/src/types/IRoomService.ts (3)
packages/core-typings/src/IRoom.ts (1)
  • IRoom (21-95)
packages/core-typings/src/IUser.ts (1)
  • IUser (186-256)
packages/core-typings/src/ISubscription.ts (1)
  • ISubscription (11-79)
apps/meteor/app/lib/server/functions/createRoom.ts (3)
ee/packages/federation-matrix/src/FederationMatrix.ts (1)
  • FederationMatrix (136-929)
ee/packages/federation-matrix/src/index.ts (1)
  • FederationMatrix (3-3)
packages/core-services/src/index.ts (2)
  • FederationMatrix (199-199)
  • Room (169-169)
ee/packages/federation-matrix/src/FederationMatrix.ts (3)
packages/core-typings/src/IUser.ts (2)
  • IUser (186-256)
  • isUserNativeFederated (277-278)
packages/core-typings/src/IRoom.ts (2)
  • IRoom (21-95)
  • isRoomNativeFederated (125-126)
packages/core-services/src/index.ts (1)
  • Room (169-169)
apps/meteor/server/services/room/service.ts (7)
packages/core-typings/src/IRoom.ts (1)
  • IRoom (21-95)
packages/core-typings/src/IUser.ts (1)
  • IUser (186-256)
apps/meteor/app/lib/server/functions/removeUserFromRoom.ts (1)
  • performUserRemoval (18-68)
packages/core-typings/src/ISubscription.ts (1)
  • ISubscription (11-79)
apps/meteor/app/lib/server/functions/acceptRoomInvite.ts (1)
  • performAcceptRoomInvite (20-61)
apps/meteor/app/lib/server/lib/notifyListener.ts (1)
  • notifyOnSubscriptionChangedById (535-544)
packages/core-services/src/index.ts (1)
  • Message (184-184)
apps/meteor/ee/server/hooks/federation/index.ts (5)
ee/packages/federation-matrix/src/events/room.ts (1)
  • room (8-88)
packages/core-typings/src/IRoom.ts (3)
  • isRoomNativeFederated (125-126)
  • IRoom (21-95)
  • IRoomNativeFederated (114-121)
ee/packages/federation-matrix/src/events/member.ts (1)
  • member (240-263)
packages/core-typings/src/IUser.ts (2)
  • isUserNativeFederated (277-278)
  • IUser (186-256)
apps/meteor/lib/callbacks/beforeCreateRoomCallback.ts (1)
  • prepareCreateRoomCallback (8-9)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (3)
  • GitHub Check: 📦 Build Packages
  • GitHub Check: CodeQL-Build
  • GitHub Check: CodeQL-Build

Comment on lines +1087 to +1094
200: ajv.compile<void>({
type: 'object',
properties: {
success: { type: 'boolean', enum: [true] },
},
required: ['success'],
additionalProperties: false,
}),
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Response schema declares void but returns object with success.

The 200 response validator (line 1087) is typed as ajv.compile<void> but the schema defines an object with a success boolean property. The generic type should match the schema.

-      200: ajv.compile<void>({
+      200: ajv.compile<{ success: true }>({
         type: 'object',
         properties: {
           success: { type: 'boolean', enum: [true] },
         },
         required: ['success'],
         additionalProperties: false,
       }),
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
200: ajv.compile<void>({
type: 'object',
properties: {
success: { type: 'boolean', enum: [true] },
},
required: ['success'],
additionalProperties: false,
}),
200: ajv.compile<{ success: true }>({
type: 'object',
properties: {
success: { type: 'boolean', enum: [true] },
},
required: ['success'],
additionalProperties: false,
}),
🤖 Prompt for AI Agents
In apps/meteor/app/api/server/v1/rooms.ts around lines 1087 to 1094, the 200
response ajv.compile is typed as ajv.compile<void> but the JSON schema defines
an object with a success:boolean property; update the generic to match the
schema (e.g. ajv.compile<{ success: boolean }>) so the TypeScript type reflects
the validated response, and ensure any callers/return types align with the new
typed shape.

Comment on lines +50 to +60
if (room.t === 'c' || room.t === 'p') {
process.nextTick(async () => {
// Add a new event, with an optional inviter
await callbacks.run('afterAddedToRoom', { user, inviter }, room);

// Keep the current event
await callbacks.run('afterJoinRoom', user, room);

void Apps.self?.triggerEvent(AppEvents.IPostRoomUserJoined, room, user, inviter);
});
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Unhandled promise rejections in deferred callbacks.

The process.nextTick callback runs async operations but errors within it are not caught. If any callback or app event fails, the error will become an unhandled promise rejection.

Consider wrapping the deferred logic in a try-catch:

 if (room.t === 'c' || room.t === 'p') {
   process.nextTick(async () => {
-    // Add a new event, with an optional inviter
-    await callbacks.run('afterAddedToRoom', { user, inviter }, room);
-
-    // Keep the current event
-    await callbacks.run('afterJoinRoom', user, room);
-
-    void Apps.self?.triggerEvent(AppEvents.IPostRoomUserJoined, room, user, inviter);
+    try {
+      await callbacks.run('afterAddedToRoom', { user, inviter }, room);
+      await callbacks.run('afterJoinRoom', user, room);
+      void Apps.self?.triggerEvent(AppEvents.IPostRoomUserJoined, room, user, inviter);
+    } catch (error) {
+      // Log error but don't propagate since this is a deferred callback
+      console.error('Error in post-join callbacks:', error);
+    }
   });
 }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
if (room.t === 'c' || room.t === 'p') {
process.nextTick(async () => {
// Add a new event, with an optional inviter
await callbacks.run('afterAddedToRoom', { user, inviter }, room);
// Keep the current event
await callbacks.run('afterJoinRoom', user, room);
void Apps.self?.triggerEvent(AppEvents.IPostRoomUserJoined, room, user, inviter);
});
}
if (room.t === 'c' || room.t === 'p') {
process.nextTick(async () => {
try {
await callbacks.run('afterAddedToRoom', { user, inviter }, room);
await callbacks.run('afterJoinRoom', user, room);
void Apps.self?.triggerEvent(AppEvents.IPostRoomUserJoined, room, user, inviter);
} catch (error) {
console.error('Error in post-join callbacks:', error);
}
});
}
🤖 Prompt for AI Agents
In apps/meteor/app/lib/server/functions/acceptRoomInvite.ts around lines 50–60,
the process.nextTick callback executes async operations without error handling
causing possible unhandled promise rejections; wrap the entire async body in a
try/catch, catch and handle/log any errors from callbacks.run and
Apps.self.triggerEvent (do not let them bubble), and ensure the catch logs the
error context (which room/user/inviter) and prevents an unhandled rejection.

},
},
required: ['type', 'content', 'sender', 'room_id', 'origin_server_ts', 'depth', 'prev_events', 'auth_events', 'origin'],
required: ['type', 'content', 'sender', 'room_id', 'origin_server_ts', 'depth', 'prev_events', 'auth_events'],
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

🏁 Script executed:

cat -n ee/packages/federation-matrix/src/api/_matrix/invite.ts | head -80 | tail -30

Repository: RocketChat/Rocket.Chat

Length of output: 824


🏁 Script executed:

# Let's see the full schema definition context
cat -n ee/packages/federation-matrix/src/api/_matrix/invite.ts

Repository: RocketChat/Rocket.Chat

Length of output: 6549


🏁 Script executed:

# Search for EventBaseSchema definition
rg "EventBaseSchema" ee/packages/federation-matrix --type ts -B 5 -A 10

Repository: RocketChat/Rocket.Chat

Length of output: 8918


🏁 Script executed:

# Check if there are schema files in the federation-matrix package
fd "schema\|event" ee/packages/federation-matrix/src --type f

Repository: RocketChat/Rocket.Chat

Length of output: 48


🌐 Web query:

Matrix federation specification event origin field required member

💡 Result:

Short answer: Yes — the federation spec requires an "origin" field. The Server‑Server API defines "origin" as a required string in federation transactions and in join/make_join/send_join payloads (it must be the sending/resident homeserver name). [1][2]


🏁 Script executed:

# Check git history to see if origin was deliberately removed from required
git log --oneline -p ee/packages/federation-matrix/src/api/_matrix/invite.ts | head -100

Repository: RocketChat/Rocket.Chat

Length of output: 2283


🏁 Script executed:

# Check other event schemas in the codebase to understand the pattern
rg "required.*origin" ee/packages/federation-matrix --type ts -B 5 -A 2

Repository: RocketChat/Rocket.Chat

Length of output: 6060


🏁 Script executed:

# Double-check the send-join schema to confirm origin is required there
sed -n '1,150p' ee/packages/federation-matrix/src/api/_matrix/send-join.ts | grep -A 60 "EventBaseSchema = {"

Repository: RocketChat/Rocket.Chat

Length of output: 896


Add origin to the required fields array in EventBaseSchema.

The origin field is defined in the schema but not marked as required, which violates the Matrix federation specification and is inconsistent with other similar event schemas in this package (send-join.ts, send-leave.ts, transactions.ts, profiles.ts all require origin). Update line 65 to include 'origin' in the required array.

🤖 Prompt for AI Agents
In ee/packages/federation-matrix/src/api/_matrix/invite.ts around line 65, the
EventBaseSchema required array is missing the 'origin' field; add 'origin' to
the required list so the schema matches the Matrix federation spec and other
event schemas (e.g., send-join.ts), ensuring incoming events must include
origin.

ggazzo
ggazzo previously approved these changes Dec 9, 2025
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

Disabled knowledge base sources:

  • Jira integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between 78f37b5 and f09e1f2.

📒 Files selected for processing (1)
  • apps/meteor/app/lib/server/functions/createRoom.ts (6 hunks)
🧰 Additional context used
📓 Path-based instructions (1)
**/*.{ts,tsx,js}

📄 CodeRabbit inference engine (.cursor/rules/playwright.mdc)

**/*.{ts,tsx,js}: Write concise, technical TypeScript/JavaScript with accurate typing in Playwright tests
Avoid code comments in the implementation

Files:

  • apps/meteor/app/lib/server/functions/createRoom.ts
🧠 Learnings (8)
📓 Common learnings
Learnt from: sampaiodiego
Repo: RocketChat/Rocket.Chat PR: 37532
File: ee/packages/federation-matrix/src/FederationMatrix.ts:920-927
Timestamp: 2025-12-09T20:01:00.324Z
Learning: In Rocket.Chat's federation invite handling (ee/packages/federation-matrix/src/FederationMatrix.ts), when a user rejects an invite via federationSDK.rejectInvite(), the subscription cleanup happens automatically through an event-driven flow: Matrix emits a leave event back, which is processed by handleLeave() in ee/packages/federation-matrix/src/events/member.ts, and that function calls Room.performUserRemoval() to clean up the subscription. No explicit cleanup is needed in the reject branch of handleInvite() because the leave event handler takes care of it.
<!-- </add_learning>
Learnt from: ricardogarim
Repo: RocketChat/Rocket.Chat PR: 37377
File: apps/meteor/ee/server/hooks/federation/index.ts:86-88
Timestamp: 2025-11-04T16:49:19.107Z
Learning: In Rocket.Chat's federation system (apps/meteor/ee/server/hooks/federation/), permission checks follow two distinct patterns: (1) User-initiated federation actions (creating rooms, adding users to federated rooms, joining from invites) should throw MeteorError to inform users they lack 'access-federation' permission. (2) Remote server-initiated federation events should silently skip/ignore when users lack permission. The beforeAddUserToRoom hook only executes for local user-initiated actions, so throwing an error there is correct. Remote federation events are handled separately by the federation Matrix package with silent skipping logic.
Learnt from: ricardogarim
Repo: RocketChat/Rocket.Chat PR: 37205
File: ee/packages/federation-matrix/src/FederationMatrix.ts:296-301
Timestamp: 2025-10-28T16:53:42.761Z
Learning: In the Rocket.Chat federation-matrix integration (ee/packages/federation-matrix/), the createRoom method from rocket.chat/federation-sdk will support a 4-argument signature (userId, roomName, visibility, displayName) in newer versions. Code using this 4-argument call is forward-compatible with planned library updates and should not be flagged as an error.
Learnt from: ricardogarim
Repo: RocketChat/Rocket.Chat PR: 37205
File: ee/packages/federation-matrix/src/FederationMatrix.ts:296-301
Timestamp: 2025-10-28T16:53:42.761Z
Learning: In the Rocket.Chat federation-matrix integration (ee/packages/federation-matrix/), the createRoom method from rocket.chat/federation-sdk will support a 4-argument signature (userId, roomName, visibility, displayName) in newer versions. Code using this 4-argument call is forward-compatible with planned library updates and should not be flagged as an error.
📚 Learning: 2025-10-28T16:53:42.761Z
Learnt from: ricardogarim
Repo: RocketChat/Rocket.Chat PR: 37205
File: ee/packages/federation-matrix/src/FederationMatrix.ts:296-301
Timestamp: 2025-10-28T16:53:42.761Z
Learning: In the Rocket.Chat federation-matrix integration (ee/packages/federation-matrix/), the createRoom method from rocket.chat/federation-sdk will support a 4-argument signature (userId, roomName, visibility, displayName) in newer versions. Code using this 4-argument call is forward-compatible with planned library updates and should not be flagged as an error.

Applied to files:

  • apps/meteor/app/lib/server/functions/createRoom.ts
📚 Learning: 2025-11-04T16:49:19.107Z
Learnt from: ricardogarim
Repo: RocketChat/Rocket.Chat PR: 37377
File: apps/meteor/ee/server/hooks/federation/index.ts:86-88
Timestamp: 2025-11-04T16:49:19.107Z
Learning: In Rocket.Chat's federation system (apps/meteor/ee/server/hooks/federation/), permission checks follow two distinct patterns: (1) User-initiated federation actions (creating rooms, adding users to federated rooms, joining from invites) should throw MeteorError to inform users they lack 'access-federation' permission. (2) Remote server-initiated federation events should silently skip/ignore when users lack permission. The beforeAddUserToRoom hook only executes for local user-initiated actions, so throwing an error there is correct. Remote federation events are handled separately by the federation Matrix package with silent skipping logic.

Applied to files:

  • apps/meteor/app/lib/server/functions/createRoom.ts
📚 Learning: 2025-12-09T20:01:00.324Z
Learnt from: sampaiodiego
Repo: RocketChat/Rocket.Chat PR: 37532
File: ee/packages/federation-matrix/src/FederationMatrix.ts:920-927
Timestamp: 2025-12-09T20:01:00.324Z
Learning: In Rocket.Chat's federation invite handling (ee/packages/federation-matrix/src/FederationMatrix.ts), when a user rejects an invite via federationSDK.rejectInvite(), the subscription cleanup happens automatically through an event-driven flow: Matrix emits a leave event back, which is processed by handleLeave() in ee/packages/federation-matrix/src/events/member.ts, and that function calls Room.performUserRemoval() to clean up the subscription. No explicit cleanup is needed in the reject branch of handleInvite() because the leave event handler takes care of it.
<!-- </add_learning>

Applied to files:

  • apps/meteor/app/lib/server/functions/createRoom.ts
📚 Learning: 2025-09-19T15:15:04.642Z
Learnt from: rodrigok
Repo: RocketChat/Rocket.Chat PR: 36991
File: apps/meteor/server/services/federation/infrastructure/rocket-chat/adapters/Settings.ts:219-221
Timestamp: 2025-09-19T15:15:04.642Z
Learning: The Federation_Matrix_homeserver_domain setting in apps/meteor/server/services/federation/infrastructure/rocket-chat/adapters/Settings.ts is part of the old federation system and is being deprecated/removed, so configuration issues with this setting should not be flagged for improvement.

Applied to files:

  • apps/meteor/app/lib/server/functions/createRoom.ts
📚 Learning: 2025-09-25T09:59:26.461Z
Learnt from: Dnouv
Repo: RocketChat/Rocket.Chat PR: 37057
File: packages/apps-engine/src/definition/accessors/IUserRead.ts:23-27
Timestamp: 2025-09-25T09:59:26.461Z
Learning: AppUserBridge.getUserRoomIds in apps/meteor/app/apps/server/bridges/users.ts always returns an array of strings (mapping subscription documents to room IDs), never undefined, even when user has no room subscriptions.

Applied to files:

  • apps/meteor/app/lib/server/functions/createRoom.ts
📚 Learning: 2025-09-25T09:59:26.461Z
Learnt from: Dnouv
Repo: RocketChat/Rocket.Chat PR: 37057
File: packages/apps-engine/src/definition/accessors/IUserRead.ts:23-27
Timestamp: 2025-09-25T09:59:26.461Z
Learning: AppUserBridge.getUserRoomIds in apps/meteor/app/apps/server/bridges/users.ts always returns an array of strings by mapping subscription documents to room IDs, never undefined, even when user has no room subscriptions.

Applied to files:

  • apps/meteor/app/lib/server/functions/createRoom.ts
📚 Learning: 2025-11-05T21:04:35.787Z
Learnt from: sampaiodiego
Repo: RocketChat/Rocket.Chat PR: 37357
File: ee/packages/federation-matrix/src/setup.ts:103-120
Timestamp: 2025-11-05T21:04:35.787Z
Learning: In Rocket.Chat's federation-matrix setup (ee/packages/federation-matrix/src/setup.ts and apps/meteor/ee/server/startup/federation.ts), configureFederationMatrixSettings does not need to be called before setupFederationMatrix. The SDK's init() establishes infrastructure (database, event handlers, APIs) first, and the configuration can be applied later via settings watchers before actual federation events are processed. The config only matters when events actually occur, at which point all infrastructure is already configured.

Applied to files:

  • apps/meteor/app/lib/server/functions/createRoom.ts
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (3)
  • GitHub Check: 📦 Build Packages
  • GitHub Check: CodeQL-Build
  • GitHub Check: CodeQL-Build
🔇 Additional comments (6)
apps/meteor/app/lib/server/functions/createRoom.ts (6)

3-3: LGTM!

The new imports for FederationMatrix, Message, Room, and Team from @rocket.chat/core-services are all utilized in the file.


73-80: LGTM!

The subscription creation with INVITED status and proper inviter metadata aligns well with the PR objectives for federation invite handling.


158-158: LGTM!

The extraData handling is consistent throughout the function. The federation checks (extraData.federated === true) properly guard against mixing federated users with non-federated rooms and correctly determine when federation handling is needed.

Also applies to: 169-169, 185-186


194-194: LGTM!

Using owner?._id as the fallback for creator is correct since creator should be an ID. The optional chaining handles the case where owner may be undefined for direct rooms.


299-304: Callback naming inconsistency acknowledged.

The comment explains why federation.afterCreateFederatedRoom runs before subscriptions (Matrix room must exist for invites). The naming inconsistency is noted by the developer as something to discuss. The logic itself is correct for the federation invite flow.


306-306: LGTM!

The call to createUsersSubscriptions correctly passes all required parameters including the new shouldBeHandledByFederation flag.

Comment on lines +61 to +71
// Invite federated members to the room SYNCRONOUSLY,
// since we do not use to invite lots of users at once, this is acceptable.
const membersToInvite = members.filter((m) => m !== owner.username);

await FederationMatrix.ensureFederatedUsersExistLocally(membersToInvite);

for await (const memberUsername of membersToInvite) {
const member = await Users.findOneByUsername(memberUsername);
if (!member) {
throw new Error('Federated user not found locally');
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Inconsistent error type and typo.

  1. "SYNCRONOUSLY" should be "SYNCHRONOUSLY".
  2. The error thrown is a generic Error while the rest of the file uses Meteor.Error. This inconsistency may cause issues with error handling middleware that expects Meteor.Error.
-		// Invite federated members to the room SYNCRONOUSLY,
-		// since we do not use to invite lots of users at once, this is acceptable.
+		// Invite federated members to the room SYNCHRONOUSLY,
+		// since we do not use to invite lots of users at once, this is acceptable.
		const membersToInvite = members.filter((m) => m !== owner.username);

		await FederationMatrix.ensureFederatedUsersExistLocally(membersToInvite);

		for await (const memberUsername of membersToInvite) {
			const member = await Users.findOneByUsername(memberUsername);
			if (!member) {
-				throw new Error('Federated user not found locally');
+				throw new Meteor.Error('error-federated-user-not-found', 'Federated user not found locally', {
+					method: 'createRoom',
+				});
			}
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
// Invite federated members to the room SYNCRONOUSLY,
// since we do not use to invite lots of users at once, this is acceptable.
const membersToInvite = members.filter((m) => m !== owner.username);
await FederationMatrix.ensureFederatedUsersExistLocally(membersToInvite);
for await (const memberUsername of membersToInvite) {
const member = await Users.findOneByUsername(memberUsername);
if (!member) {
throw new Error('Federated user not found locally');
}
// Invite federated members to the room SYNCHRONOUSLY,
// since we do not use to invite lots of users at once, this is acceptable.
const membersToInvite = members.filter((m) => m !== owner.username);
await FederationMatrix.ensureFederatedUsersExistLocally(membersToInvite);
for await (const memberUsername of membersToInvite) {
const member = await Users.findOneByUsername(memberUsername);
if (!member) {
throw new Meteor.Error('error-federated-user-not-found', 'Federated user not found locally', {
method: 'createRoom',
});
}
🤖 Prompt for AI Agents
In apps/meteor/app/lib/server/functions/createRoom.ts around lines 61 to 71, fix
the typo "SYNCRONOUSLY" -> "SYNCHRONOUSLY" and replace the thrown generic Error
with a Meteor.Error so it matches the rest of the file’s error handling; update
the throw to use new Meteor.Error with an appropriate error code and descriptive
message (e.g. 'federated-user-not-found', 'Federated user not found locally') so
middleware expecting Meteor.Error will handle it correctly.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 4

♻️ Duplicate comments (1)
apps/meteor/ee/server/hooks/federation/index.ts (1)

115-118: Permission check still applied to invited user instead of inviter.

The permission check on line 116 validates user._id (the invited user) rather than inviter._id (the actor). This was previously flagged and marked as addressed, but the current code still checks the wrong user ID.

Per retrieved learnings, user-initiated federation actions should validate the initiating user's permissions, not the target user's.

Apply this diff:

-		if (!(await Authorization.hasPermission(user._id, 'access-federation'))) {
+		if (!(await Authorization.hasPermission(inviter._id, 'access-federation'))) {
 			throw new MeteorError('error-not-authorized-federation', 'Not authorized to access federation');
 		}
🧹 Nitpick comments (1)
apps/meteor/ee/server/hooks/federation/index.ts (1)

272-272: Consider defensive null-check for room.federation.

While FederationActions.shouldPerformFederationAction(room) and prepareCreateRoomCallback should ensure room.federation exists, using optional chaining would make this code more resilient to unexpected state.

Apply this diff:

-		if (!room.federation.mrid) {
+		if (!room.federation?.mrid) {
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

Disabled knowledge base sources:

  • Jira integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between f09e1f2 and ff339d3.

📒 Files selected for processing (1)
  • apps/meteor/ee/server/hooks/federation/index.ts (4 hunks)
🧰 Additional context used
📓 Path-based instructions (1)
**/*.{ts,tsx,js}

📄 CodeRabbit inference engine (.cursor/rules/playwright.mdc)

**/*.{ts,tsx,js}: Write concise, technical TypeScript/JavaScript with accurate typing in Playwright tests
Avoid code comments in the implementation

Files:

  • apps/meteor/ee/server/hooks/federation/index.ts
🧠 Learnings (11)
📓 Common learnings
Learnt from: sampaiodiego
Repo: RocketChat/Rocket.Chat PR: 37532
File: ee/packages/federation-matrix/src/FederationMatrix.ts:920-927
Timestamp: 2025-12-09T20:01:00.324Z
Learning: In Rocket.Chat's federation invite handling (ee/packages/federation-matrix/src/FederationMatrix.ts), when a user rejects an invite via federationSDK.rejectInvite(), the subscription cleanup happens automatically through an event-driven flow: Matrix emits a leave event back, which is processed by handleLeave() in ee/packages/federation-matrix/src/events/member.ts, and that function calls Room.performUserRemoval() to clean up the subscription. No explicit cleanup is needed in the reject branch of handleInvite() because the leave event handler takes care of it.
<!-- </add_learning>
Learnt from: ricardogarim
Repo: RocketChat/Rocket.Chat PR: 37377
File: apps/meteor/ee/server/hooks/federation/index.ts:86-88
Timestamp: 2025-11-04T16:49:19.107Z
Learning: In Rocket.Chat's federation system (apps/meteor/ee/server/hooks/federation/), permission checks follow two distinct patterns: (1) User-initiated federation actions (creating rooms, adding users to federated rooms, joining from invites) should throw MeteorError to inform users they lack 'access-federation' permission. (2) Remote server-initiated federation events should silently skip/ignore when users lack permission. The beforeAddUserToRoom hook only executes for local user-initiated actions, so throwing an error there is correct. Remote federation events are handled separately by the federation Matrix package with silent skipping logic.
Learnt from: ricardogarim
Repo: RocketChat/Rocket.Chat PR: 37205
File: ee/packages/federation-matrix/src/FederationMatrix.ts:296-301
Timestamp: 2025-10-28T16:53:42.761Z
Learning: In the Rocket.Chat federation-matrix integration (ee/packages/federation-matrix/), the createRoom method from rocket.chat/federation-sdk will support a 4-argument signature (userId, roomName, visibility, displayName) in newer versions. Code using this 4-argument call is forward-compatible with planned library updates and should not be flagged as an error.
Learnt from: ricardogarim
Repo: RocketChat/Rocket.Chat PR: 37205
File: ee/packages/federation-matrix/src/FederationMatrix.ts:296-301
Timestamp: 2025-10-28T16:53:42.761Z
Learning: In the Rocket.Chat federation-matrix integration (ee/packages/federation-matrix/), the createRoom method from rocket.chat/federation-sdk will support a 4-argument signature (userId, roomName, visibility, displayName) in newer versions. Code using this 4-argument call is forward-compatible with planned library updates and should not be flagged as an error.
📚 Learning: 2025-11-04T16:49:19.107Z
Learnt from: ricardogarim
Repo: RocketChat/Rocket.Chat PR: 37377
File: apps/meteor/ee/server/hooks/federation/index.ts:86-88
Timestamp: 2025-11-04T16:49:19.107Z
Learning: In Rocket.Chat's federation system (apps/meteor/ee/server/hooks/federation/), permission checks follow two distinct patterns: (1) User-initiated federation actions (creating rooms, adding users to federated rooms, joining from invites) should throw MeteorError to inform users they lack 'access-federation' permission. (2) Remote server-initiated federation events should silently skip/ignore when users lack permission. The beforeAddUserToRoom hook only executes for local user-initiated actions, so throwing an error there is correct. Remote federation events are handled separately by the federation Matrix package with silent skipping logic.

Applied to files:

  • apps/meteor/ee/server/hooks/federation/index.ts
📚 Learning: 2025-10-28T16:53:42.761Z
Learnt from: ricardogarim
Repo: RocketChat/Rocket.Chat PR: 37205
File: ee/packages/federation-matrix/src/FederationMatrix.ts:296-301
Timestamp: 2025-10-28T16:53:42.761Z
Learning: In the Rocket.Chat federation-matrix integration (ee/packages/federation-matrix/), the createRoom method from rocket.chat/federation-sdk will support a 4-argument signature (userId, roomName, visibility, displayName) in newer versions. Code using this 4-argument call is forward-compatible with planned library updates and should not be flagged as an error.

Applied to files:

  • apps/meteor/ee/server/hooks/federation/index.ts
📚 Learning: 2025-09-19T15:15:04.642Z
Learnt from: rodrigok
Repo: RocketChat/Rocket.Chat PR: 36991
File: apps/meteor/server/services/federation/infrastructure/rocket-chat/adapters/Settings.ts:219-221
Timestamp: 2025-09-19T15:15:04.642Z
Learning: The Federation_Matrix_homeserver_domain setting in apps/meteor/server/services/federation/infrastructure/rocket-chat/adapters/Settings.ts is part of the old federation system and is being deprecated/removed, so configuration issues with this setting should not be flagged for improvement.

Applied to files:

  • apps/meteor/ee/server/hooks/federation/index.ts
📚 Learning: 2025-11-05T21:04:35.787Z
Learnt from: sampaiodiego
Repo: RocketChat/Rocket.Chat PR: 37357
File: ee/packages/federation-matrix/src/setup.ts:103-120
Timestamp: 2025-11-05T21:04:35.787Z
Learning: In Rocket.Chat's federation-matrix setup (ee/packages/federation-matrix/src/setup.ts and apps/meteor/ee/server/startup/federation.ts), configureFederationMatrixSettings does not need to be called before setupFederationMatrix. The SDK's init() establishes infrastructure (database, event handlers, APIs) first, and the configuration can be applied later via settings watchers before actual federation events are processed. The config only matters when events actually occur, at which point all infrastructure is already configured.

Applied to files:

  • apps/meteor/ee/server/hooks/federation/index.ts
📚 Learning: 2025-12-09T20:01:00.324Z
Learnt from: sampaiodiego
Repo: RocketChat/Rocket.Chat PR: 37532
File: ee/packages/federation-matrix/src/FederationMatrix.ts:920-927
Timestamp: 2025-12-09T20:01:00.324Z
Learning: In Rocket.Chat's federation invite handling (ee/packages/federation-matrix/src/FederationMatrix.ts), when a user rejects an invite via federationSDK.rejectInvite(), the subscription cleanup happens automatically through an event-driven flow: Matrix emits a leave event back, which is processed by handleLeave() in ee/packages/federation-matrix/src/events/member.ts, and that function calls Room.performUserRemoval() to clean up the subscription. No explicit cleanup is needed in the reject branch of handleInvite() because the leave event handler takes care of it.
<!-- </add_learning>

Applied to files:

  • apps/meteor/ee/server/hooks/federation/index.ts
📚 Learning: 2025-09-25T09:59:26.461Z
Learnt from: Dnouv
Repo: RocketChat/Rocket.Chat PR: 37057
File: packages/apps-engine/src/definition/accessors/IUserRead.ts:23-27
Timestamp: 2025-09-25T09:59:26.461Z
Learning: UserBridge.doGetUserRoomIds in packages/apps-engine/src/server/bridges/UserBridge.ts has a bug where it implicitly returns undefined when the app lacks read permission (missing return statement in the else case of the permission check).

Applied to files:

  • apps/meteor/ee/server/hooks/federation/index.ts
📚 Learning: 2025-11-19T18:20:37.116Z
Learnt from: gabriellsh
Repo: RocketChat/Rocket.Chat PR: 37419
File: apps/meteor/server/services/media-call/service.ts:141-141
Timestamp: 2025-11-19T18:20:37.116Z
Learning: In apps/meteor/server/services/media-call/service.ts, the sendHistoryMessage method should use call.caller.id or call.createdBy?.id as the message author, not call.transferredBy?.id. Even for transferred calls, the message should appear in the DM between the two users who are calling each other, not sent by the person who transferred the call.

Applied to files:

  • apps/meteor/ee/server/hooks/federation/index.ts
📚 Learning: 2025-09-25T09:59:26.461Z
Learnt from: Dnouv
Repo: RocketChat/Rocket.Chat PR: 37057
File: packages/apps-engine/src/definition/accessors/IUserRead.ts:23-27
Timestamp: 2025-09-25T09:59:26.461Z
Learning: AppUserBridge.getUserRoomIds in apps/meteor/app/apps/server/bridges/users.ts always returns an array of strings (mapping subscription documents to room IDs), never undefined, even when user has no room subscriptions.

Applied to files:

  • apps/meteor/ee/server/hooks/federation/index.ts
📚 Learning: 2025-09-25T09:59:26.461Z
Learnt from: Dnouv
Repo: RocketChat/Rocket.Chat PR: 37057
File: packages/apps-engine/src/definition/accessors/IUserRead.ts:23-27
Timestamp: 2025-09-25T09:59:26.461Z
Learning: AppUserBridge.getUserRoomIds in apps/meteor/app/apps/server/bridges/users.ts always returns an array of strings by mapping subscription documents to room IDs, never undefined, even when user has no room subscriptions.

Applied to files:

  • apps/meteor/ee/server/hooks/federation/index.ts
📚 Learning: 2025-11-27T17:56:26.050Z
Learnt from: MartinSchoeler
Repo: RocketChat/Rocket.Chat PR: 37557
File: apps/meteor/client/views/admin/ABAC/AdminABACRooms.tsx:115-116
Timestamp: 2025-11-27T17:56:26.050Z
Learning: In Rocket.Chat, the GET /v1/abac/rooms endpoint (implemented in ee/packages/abac/src/index.ts) only returns rooms where abacAttributes exists and is not an empty array (query: { abacAttributes: { $exists: true, $ne: [] } }). Therefore, in components consuming this endpoint (like AdminABACRooms.tsx), room.abacAttributes is guaranteed to be defined for all returned rooms, and optional chaining before calling array methods like .join() is sufficient without additional null coalescing.

Applied to files:

  • apps/meteor/ee/server/hooks/federation/index.ts
🧬 Code graph analysis (1)
apps/meteor/ee/server/hooks/federation/index.ts (4)
ee/packages/federation-matrix/src/FederationMatrix.ts (1)
  • FederationMatrix (136-929)
packages/core-typings/src/IRoom.ts (3)
  • isRoomNativeFederated (125-126)
  • IRoom (21-95)
  • IRoomNativeFederated (114-121)
packages/core-typings/src/IUser.ts (2)
  • isUserNativeFederated (277-278)
  • IUser (186-256)
apps/meteor/lib/callbacks/beforeCreateRoomCallback.ts (1)
  • prepareCreateRoomCallback (8-9)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (3)
  • GitHub Check: 📦 Build Packages
  • GitHub Check: CodeQL-Build
  • GitHub Check: CodeQL-Build

} else {
// TODO unify how to get server
// matrix room was already created and passed
const fromServer = federatedRoomId.split(':')[1];
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Validate federatedRoomId format before extracting server.

The code assumes federatedRoomId follows the format !id:server and directly accesses split(':')[1]. If the ID is malformed or doesn't contain a colon, this will return undefined, potentially causing Rooms.setAsFederated to receive an invalid origin value.

Apply this diff to add validation:

-		const fromServer = federatedRoomId.split(':')[1];
+		const parts = federatedRoomId.split(':');
+		if (parts.length < 2) {
+			throw new MeteorError('error-invalid-federation-id', 'Invalid federated room ID format');
+		}
+		const fromServer = parts[1];
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
const fromServer = federatedRoomId.split(':')[1];
const parts = federatedRoomId.split(':');
if (parts.length < 2) {
throw new MeteorError('error-invalid-federation-id', 'Invalid federated room ID format');
}
const fromServer = parts[1];
🤖 Prompt for AI Agents
In apps/meteor/ee/server/hooks/federation/index.ts around line 32, the code
unconditionally does const fromServer = federatedRoomId.split(':')[1]; which can
yield undefined for malformed IDs; validate the federatedRoomId contains a colon
and at least two parts before extracting the server part. If validation fails,
handle it by logging an error and aborting the operation (or returning early) so
Rooms.setAsFederated is not called with an invalid origin; otherwise assign
fromServer from the second split part and proceed.

Comment on lines +91 to 103
beforeAddUsersToRoom.add(async ({ usernames, inviter }, room) => {
if (!FederationActions.shouldPerformFederationAction(room) && inviter) {
// check if trying to invite a federated user to a non-federated room
const federatedUsernames = usernames.filter((u) => validateFederatedUsername(u));
if (federatedUsernames.length > 0) {
throw new MeteorError('error-federated-users-in-non-federated-rooms', 'Cannot add federated users to non-federated rooms');
}
return;
}

// we create local users before adding them to the room
await FederationMatrix.ensureFederatedUsersExistLocally(usernames);
});
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Search for the beforeAddUsersToRoom hook definition and usage patterns
rg -n 'beforeAddUsersToRoom' apps/meteor/ee/server/hooks/federation/ -A 5 -B 2

Repository: RocketChat/Rocket.Chat

Length of output: 2087


🏁 Script executed:

#!/bin/bash
# Search for calls to the hook callback or room event triggers with usernames
rg -n 'addUserToRoom|addUsersToRoom' apps/meteor/ee/server/ --type ts | head -30

Repository: RocketChat/Rocket.Chat

Length of output: 501


🏁 Script executed:

#!/bin/bash
# Look for federation-related user addition patterns
rg -n 'inviter\s*:' apps/meteor/ee/server/hooks/federation/ --type ts -B 3 -A 3

Repository: RocketChat/Rocket.Chat

Length of output: 48


🏁 Script executed:

#!/bin/bash
# Check the Room model to understand addUsersToRoom method
fd -e ts -e js 'room' apps/meteor | xargs rg -l 'addUsersToRoom' | head -10

Repository: RocketChat/Rocket.Chat

Length of output: 209


🏁 Script executed:

#!/bin/bash
# Check the addUsersToRoom method implementation
cat -n apps/meteor/app/lib/server/methods/addUsersToRoom.ts | head -60

Repository: RocketChat/Rocket.Chat

Length of output: 2484


🏁 Script executed:

#!/bin/bash
# Also check addUserToRoom for comparison
cat -n apps/meteor/app/lib/server/methods/addUserToRoom.ts | head -80

Repository: RocketChat/Rocket.Chat

Length of output: 938


🏁 Script executed:

#!/bin/bash
# Search for beforeAddUsersToRoom callback definition to understand parameters
rg -n 'beforeAddUsersToRoom.*=' apps/meteor/lib/callbacks/ --type ts -B 2 -A 5

Repository: RocketChat/Rocket.Chat

Length of output: 559


🏁 Script executed:

#!/bin/bash
# Continue reading addUsersToRoomMethod to find the callback invocation
cat -n apps/meteor/app/lib/server/methods/addUsersToRoom.ts | head -150 | tail -100

Repository: RocketChat/Rocket.Chat

Length of output: 3539


🏁 Script executed:

#!/bin/bash
# Search for beforeAddUsersToRoom.run in the file
rg -n 'beforeAddUsersToRoom' apps/meteor/app/lib/server/methods/addUsersToRoom.ts -B 5 -A 5

Repository: RocketChat/Rocket.Chat

Length of output: 982


🏁 Script executed:

#!/bin/bash
# Search for all calls to addUsersToRoomMethod to see if user is ever undefined
rg -n 'addUsersToRoomMethod' apps/meteor/ --type ts -B 2 -A 2

Repository: RocketChat/Rocket.Chat

Length of output: 8228


🏁 Script executed:

#!/bin/bash
# Check if there are other places where beforeAddUsersToRoom is registered
rg -n 'beforeAddUsersToRoom.add\|beforeAddUsersToRoom.run' apps/meteor/ --type ts

Repository: RocketChat/Rocket.Chat

Length of output: 48


🏁 Script executed:

#!/bin/bash
# Also check the federation hook more carefully - check if there's specific handling for system actions
cat -n apps/meteor/ee/server/hooks/federation/index.ts | head -110 | tail -25

Repository: RocketChat/Rocket.Chat

Length of output: 1046


🏁 Script executed:

#!/bin/bash
# Check slashcommands-inviteall more carefully
sed -n '80,100p' apps/meteor/app/slashcommands-inviteall/server/server.ts

Repository: RocketChat/Rocket.Chat

Length of output: 803


🏁 Script executed:

#!/bin/bash
# Check slashcommands-invite more carefully
sed -n '90,110p' apps/meteor/app/slashcommands-invite/server/server.ts

Repository: RocketChat/Rocket.Chat

Length of output: 519


🏁 Script executed:

#!/bin/bash
# Check bot-helpers more carefully
sed -n '75,95p' apps/meteor/app/bot-helpers/server/index.ts

Repository: RocketChat/Rocket.Chat

Length of output: 621


Pass inviter to all addUsersToRoomMethod calls to enforce federation guards consistently.

The condition !FederationActions.shouldPerformFederationAction(room) && inviter relies on inviter being present, but several callers omit the third parameter: bot-helpers (line 85) and slashcommands-inviteall (line 93). When inviter is undefined, the federation validation bypass and federated users can be added to non-federated rooms. All calls to addUsersToRoomMethod should pass the inviter parameter to ensure the federation security check is consistently applied.

🤖 Prompt for AI Agents
In apps/meteor/ee/server/hooks/federation/index.ts around lines 91–103, the
federation guard checks rely on the inviter parameter but some callers omit it;
update all calls to addUsersToRoomMethod (notably in bot-helpers and
slashcommands-inviteall) to pass the inviter argument so the federation
validation runs consistently. Locate those caller sites and forward the current
user/inviter (e.g., the user object or userId used in the caller) as the third
parameter to addUsersToRoomMethod; if the caller only has a userId, pass the
corresponding user or ensure addUsersToRoomMethod accepts the same inviter shape
used by the hook.

// TODO: use a shared helper to check whether a user is federated
// since the DM creation API doesn't tell us if the room is federated (unlike normal channels),
// we're currently inferring it: if any participant has a Matrix-style ID (@user:server), we treat the DM as federated
const hasFederatedMembers = roomUsers.some((user: unknown) => typeof user === 'string' && user.includes(':') && user.includes('@'));
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion | 🟠 Major

Use validateFederatedUsername for consistency.

The check typeof user === 'string' && user.includes(':') && user.includes('@') is less strict than validateFederatedUsername used elsewhere in this file (line 94). This could incorrectly classify usernames like "test:@" as federated.

Apply this diff to use the imported validator:

-	const hasFederatedMembers = roomUsers.some((user: unknown) => typeof user === 'string' && user.includes(':') && user.includes('@'));
+	const hasFederatedMembers = roomUsers.some((user: unknown) => typeof user === 'string' && validateFederatedUsername(user));
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
const hasFederatedMembers = roomUsers.some((user: unknown) => typeof user === 'string' && user.includes(':') && user.includes('@'));
const hasFederatedMembers = roomUsers.some((user: unknown) => typeof user === 'string' && validateFederatedUsername(user));
🤖 Prompt for AI Agents
In apps/meteor/ee/server/hooks/federation/index.ts around line 254, the current
predicate uses a loose string check (typeof user === 'string' &&
user.includes(':') && user.includes('@')) which is less strict than the
project's validateFederatedUsername; change the check to use
validateFederatedUsername by first ensuring user is a string and then calling
validateFederatedUsername(user as string) so only valid federated usernames are
counted; keep the type guard to avoid runtime errors and rely on the existing
imported validator for correctness.

// when we receive extraData.federated, we need to prepare the room to be considered IRoomNativeFederated.
// according to isRoomNativeFederated for a room to be considered IRoomNativeFederated it is enough to have
// only an empty "federation" object
(extraData as IRoomNativeFederated).federation = { version: 1 } as any;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Type cast bypasses safety for incomplete federation object.

The code creates a federation object with only version, but IRoomNativeFederated.federation requires mrid and origin. The as any cast hides this mismatch from TypeScript. While the type guard isRoomNativeFederated only checks that federation exists, downstream code may attempt to access room.federation.mrid or room.federation.origin without null checks, leading to runtime errors.

Consider one of these approaches:

  1. Use a partial type to document the incomplete state:
-	(extraData as IRoomNativeFederated).federation = { version: 1 } as any;
+	extraData.federation = { version: 1 } as Partial<IRoomNativeFederated['federation']> & { version: number };
  1. Add a comment and ensure all access sites handle missing mrid/origin:
 	(extraData as IRoomNativeFederated).federation = { version: 1 } as any;
+	// NOTE: mrid and origin are set later by createRoom or setAsFederated.
+	// All code accessing federation.mrid or federation.origin must handle undefined.

Then verify all access sites with:

#!/bin/bash
# Find all accesses to federation.mrid and federation.origin to ensure they handle undefined
ast-grep --pattern $'$_.federation.mrid'
ast-grep --pattern $'$_.federation.origin'
🤖 Prompt for AI Agents
In apps/meteor/ee/server/hooks/federation/index.ts around line 289, the code
force-casts a federation object to any while only supplying version, hiding that
IRoomNativeFederated.federation requires mrid and origin; replace the unsafe
cast by assigning a properly typed partial (e.g. use
Partial<IRoomNativeFederated['federation']> or a dedicated type like { version:
number; mrid?: string; origin?: string }), or provide safe defaults for
mrid/origin if appropriate, and update the containing type if needed; then audit
all downstream accesses to federation.mrid and federation.origin to ensure they
handle undefined (add null checks or guards) and run the suggested ast-grep
search to verify no unsafe accesses remain.

@ggazzo ggazzo merged commit 1a80025 into develop Dec 10, 2025
50 of 51 checks passed
@ggazzo ggazzo deleted the feat/invites branch December 10, 2025 01:45
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

stat: QA assured Means it has been tested and approved by a company insider stat: ready to merge PR tested and approved waiting for merge

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants